All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] powerpc: catch 32/64bit mix
@ 2009-11-25 16:22 Serge E. Hallyn
       [not found] ` <20091125162250.GA9034-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Serge E. Hallyn @ 2009-11-25 16:22 UTC (permalink / raw)
  To: Oren Laadan; +Cc: Linux Containers

The arch-specific restore_thread() and restore_cpu() are called after
restore_task_obj()s.  This means that when a 32-bit task calls
sys_restart() with a 64-bit image, we'll be reloading memory mappings
before those are called, and get a 'mysterious' -EINVAL for trying to
map libc into an area > TASK_SIZE.

This patch just adds a set of arch-specific flags to the cpu_hdr_task
struct.  s390 can use this to note TIF_31BIT, and powerpc uses it to
mark TIF_32BIT.

With this patch, a 32-bit task restarting a 64-bit image at least gets
a meaningful message in the user logfile and syslog:
	32-bit task trying to restart a 64-bit one

If we keep this patch, then we'll want to drop bitness_test from
restore_cpu() in powerpc, and maybe use that code instead of the code
I used.  We also may eventually want to actually switch the task
personality.

Signed-off-by: Serge Hallyn <serue-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
---
 arch/powerpc/mm/checkpoint.c   |   30 ++++++++++++++++++++++++++++++
 arch/s390/mm/checkpoint.c      |   10 ++++++++++
 arch/x86/mm/checkpoint.c       |   10 ++++++++++
 checkpoint/process.c           |    6 ++++++
 include/linux/checkpoint.h     |    6 ++++++
 include/linux/checkpoint_hdr.h |    1 +
 6 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/mm/checkpoint.c b/arch/powerpc/mm/checkpoint.c
index de18467..ec758d9 100644
--- a/arch/powerpc/mm/checkpoint.c
+++ b/arch/powerpc/mm/checkpoint.c
@@ -207,6 +207,13 @@ static void checkpoint_dabr(struct ckpt_hdr_cpu *cpu_hdr,
 	ckpt_cpu_feature_set(cpu_hdr, CKPT_USED_DEBUG);
 }
 
+/* called early to set TIF_32BIT etc */
+void checkpoint_arch_thread(struct ckpt_hdr_task *h, struct task_struct *t)
+{
+	if (test_tsk_thread_flag(t, TIF_32BIT))
+		h->arch_flags |= CKPT_ARCH_32BIT;
+}
+
 /* dump the thread_struct of a given task */
 int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
 {
@@ -264,6 +271,29 @@ int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm)
  * Restart
  */
 
+/*
+ * Called early to check/reset TIF_32BIT etc.
+ * Eventually we want to actually set the personality, but for now we
+ * should at least catch and tell the user what happened.
+ */
+int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h)
+{
+	int me = test_thread_flag(TIF_32BIT);
+	int ckpted = (!!(h->arch_flags & CKPT_ARCH_32BIT));
+
+	/* all's we if both are 32-bit or 64-bit */
+	if (!(me ^ ckpted))
+		return 0;
+
+	if (me)
+		ckpt_err(ctx, -EINVAL,
+			 "32-bit task trying to restart a 64-bit one\n");
+	else
+		ckpt_err(ctx, -EINVAL,
+			 "64-bit task trying to restart a 32-bit one\n");
+	return -EINVAL;
+}
+
 /* read the thread_struct into the current task */
 int restore_thread(struct ckpt_ctx *ctx)
 {
diff --git a/arch/s390/mm/checkpoint.c b/arch/s390/mm/checkpoint.c
index 40dd417..639df3f 100644
--- a/arch/s390/mm/checkpoint.c
+++ b/arch/s390/mm/checkpoint.c
@@ -81,6 +81,10 @@ static void s390_mm(int op, struct ckpt_hdr_mm_context *h,
 	CKPT_COPY(op, h->asce_limit, mm->context.asce_limit);
 }
 
+/* called early to set TIF_31BIT etc */
+void checkpoint_ach_thread(struct ckpt_hdr_task *h, struct task_struct *t)
+{ }
+
 int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
 {
 	return 0;
@@ -141,6 +145,12 @@ int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm)
  * Restart
  */
 
+/* called early to check/reset TIF_31BIT etc */
+int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h)
+{
+	return 0;
+}
+
 int restore_thread(struct ckpt_ctx *ctx)
 {
 	return 0;
diff --git a/arch/x86/mm/checkpoint.c b/arch/x86/mm/checkpoint.c
index 2752fdf..5a33dfd 100644
--- a/arch/x86/mm/checkpoint.c
+++ b/arch/x86/mm/checkpoint.c
@@ -165,6 +165,10 @@ static int may_checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
 	return 0;
 }
 
+/* called early to set TIF_32BIT etc */
+void checkpoint_arch_thread(struct ckpt_hdr_task *h, struct task_struct *t)
+{ }
+
 /* dump the thread_struct of a given task */
 int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
 {
@@ -399,6 +403,12 @@ int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm)
  * Restart
  */
 
+/* called early to check/reset TIF_32BIT etc */
+int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h)
+{
+	return 0;
+}
+
 /* read the thread_struct into the current task */
 int restore_thread(struct ckpt_ctx *ctx)
 {
diff --git a/checkpoint/process.c b/checkpoint/process.c
index 4cce6f8..2ad79ee 100644
--- a/checkpoint/process.c
+++ b/checkpoint/process.c
@@ -138,6 +138,8 @@ static int checkpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t)
 	h->exit_state = t->exit_state;
 	h->exit_code = t->exit_code;
 
+	checkpoint_arch_thread(h, t);
+
 	if (t->exit_state) {
 		/* zombie - skip remaining state */
 		BUG_ON(t->exit_state != EXIT_ZOMBIE);
@@ -504,6 +506,10 @@ static int restore_task_struct(struct ckpt_ctx *ctx)
 	if (IS_ERR(h))
 		return PTR_ERR(h);
 
+	ret = restore_arch_thread(ctx, h);
+	if (ret)
+		return ret;
+
 	ret = -EINVAL;
 	if (h->state == TASK_DEAD) {
 		if (h->exit_state != EXIT_ZOMBIE)
diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
index 550f6e8..343a166 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -161,12 +161,18 @@ extern int restore_task(struct ckpt_ctx *ctx);
 extern int pre_restore_task(void);
 extern void post_restore_task(void);
 
+/* arch_thread flags */
+#define CKPT_ARCH_32BIT		0x01
+
 /* arch hooks */
+extern void checkpoint_arch_thread(struct ckpt_hdr_task *h,
+				   struct task_struct *t);
 extern int checkpoint_write_header_arch(struct ckpt_ctx *ctx);
 extern int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t);
 extern int checkpoint_cpu(struct ckpt_ctx *ctx, struct task_struct *t);
 extern int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm);
 
+extern int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h);
 extern int restore_read_header_arch(struct ckpt_ctx *ctx);
 extern int restore_thread(struct ckpt_ctx *ctx);
 extern int restore_cpu(struct ckpt_ctx *ctx);
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index 667b7aa..14976b2 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -344,6 +344,7 @@ struct ckpt_hdr_task {
 	__u32 compat_robust_futex_list; /* a compat __user ptr */
 	__u32 robust_futex_head_len;
 	__u64 robust_futex_list; /* a __user ptr */
+	__u64 arch_flags;	 /* includes ARCH_32BIT */
 } __attribute__((aligned(8)));
 
 /* Posix capabilities */
-- 
1.6.2.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH RFC] powerpc: catch 32/64bit mix
       [not found] ` <20091125162250.GA9034-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2009-11-25 19:03   ` Oren Laadan
       [not found]     ` <4B0D7F96.6050100-eQaUEPhvms7ENvBUuze7eA@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Oren Laadan @ 2009-11-25 19:03 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: Linux Containers


I can't recall a convincing reason why restore_{thread,cpu}() should
run so late, or in particular after restore_task_objs().

I think the original motivation was to avoid the point-of-no-return
at a very early stage. However this is only useful for self-restart.

If we ever want self-restart to fail gracefully should something go
wrong, we should be prepared to undo any changes to the process -
on the error path. While not beyond reach, it isn't a top priority.

Does calling restore_{thread,cpu}() earlier solve the problem ?

BTW, this is also relevant for x86-64...

Oren.


Serge E. Hallyn wrote:
> The arch-specific restore_thread() and restore_cpu() are called after
> restore_task_obj()s.  This means that when a 32-bit task calls
> sys_restart() with a 64-bit image, we'll be reloading memory mappings
> before those are called, and get a 'mysterious' -EINVAL for trying to
> map libc into an area > TASK_SIZE.
> 
> This patch just adds a set of arch-specific flags to the cpu_hdr_task
> struct.  s390 can use this to note TIF_31BIT, and powerpc uses it to
> mark TIF_32BIT.
> 
> With this patch, a 32-bit task restarting a 64-bit image at least gets
> a meaningful message in the user logfile and syslog:
> 	32-bit task trying to restart a 64-bit one
> 
> If we keep this patch, then we'll want to drop bitness_test from
> restore_cpu() in powerpc, and maybe use that code instead of the code
> I used.  We also may eventually want to actually switch the task
> personality.
> 
> Signed-off-by: Serge Hallyn <serue-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> ---
>  arch/powerpc/mm/checkpoint.c   |   30 ++++++++++++++++++++++++++++++
>  arch/s390/mm/checkpoint.c      |   10 ++++++++++
>  arch/x86/mm/checkpoint.c       |   10 ++++++++++
>  checkpoint/process.c           |    6 ++++++
>  include/linux/checkpoint.h     |    6 ++++++
>  include/linux/checkpoint_hdr.h |    1 +
>  6 files changed, 63 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/mm/checkpoint.c b/arch/powerpc/mm/checkpoint.c
> index de18467..ec758d9 100644
> --- a/arch/powerpc/mm/checkpoint.c
> +++ b/arch/powerpc/mm/checkpoint.c
> @@ -207,6 +207,13 @@ static void checkpoint_dabr(struct ckpt_hdr_cpu *cpu_hdr,
>  	ckpt_cpu_feature_set(cpu_hdr, CKPT_USED_DEBUG);
>  }
>  
> +/* called early to set TIF_32BIT etc */
> +void checkpoint_arch_thread(struct ckpt_hdr_task *h, struct task_struct *t)
> +{
> +	if (test_tsk_thread_flag(t, TIF_32BIT))
> +		h->arch_flags |= CKPT_ARCH_32BIT;
> +}
> +
>  /* dump the thread_struct of a given task */
>  int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
>  {
> @@ -264,6 +271,29 @@ int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm)
>   * Restart
>   */
>  
> +/*
> + * Called early to check/reset TIF_32BIT etc.
> + * Eventually we want to actually set the personality, but for now we
> + * should at least catch and tell the user what happened.
> + */
> +int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h)
> +{
> +	int me = test_thread_flag(TIF_32BIT);
> +	int ckpted = (!!(h->arch_flags & CKPT_ARCH_32BIT));
> +
> +	/* all's we if both are 32-bit or 64-bit */
> +	if (!(me ^ ckpted))
> +		return 0;
> +
> +	if (me)
> +		ckpt_err(ctx, -EINVAL,
> +			 "32-bit task trying to restart a 64-bit one\n");
> +	else
> +		ckpt_err(ctx, -EINVAL,
> +			 "64-bit task trying to restart a 32-bit one\n");
> +	return -EINVAL;
> +}
> +
>  /* read the thread_struct into the current task */
>  int restore_thread(struct ckpt_ctx *ctx)
>  {
> diff --git a/arch/s390/mm/checkpoint.c b/arch/s390/mm/checkpoint.c
> index 40dd417..639df3f 100644
> --- a/arch/s390/mm/checkpoint.c
> +++ b/arch/s390/mm/checkpoint.c
> @@ -81,6 +81,10 @@ static void s390_mm(int op, struct ckpt_hdr_mm_context *h,
>  	CKPT_COPY(op, h->asce_limit, mm->context.asce_limit);
>  }
>  
> +/* called early to set TIF_31BIT etc */
> +void checkpoint_ach_thread(struct ckpt_hdr_task *h, struct task_struct *t)
> +{ }
> +
>  int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
>  {
>  	return 0;
> @@ -141,6 +145,12 @@ int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm)
>   * Restart
>   */
>  
> +/* called early to check/reset TIF_31BIT etc */
> +int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h)
> +{
> +	return 0;
> +}
> +
>  int restore_thread(struct ckpt_ctx *ctx)
>  {
>  	return 0;
> diff --git a/arch/x86/mm/checkpoint.c b/arch/x86/mm/checkpoint.c
> index 2752fdf..5a33dfd 100644
> --- a/arch/x86/mm/checkpoint.c
> +++ b/arch/x86/mm/checkpoint.c
> @@ -165,6 +165,10 @@ static int may_checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
>  	return 0;
>  }
>  
> +/* called early to set TIF_32BIT etc */
> +void checkpoint_arch_thread(struct ckpt_hdr_task *h, struct task_struct *t)
> +{ }
> +
>  /* dump the thread_struct of a given task */
>  int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t)
>  {
> @@ -399,6 +403,12 @@ int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm)
>   * Restart
>   */
>  
> +/* called early to check/reset TIF_32BIT etc */
> +int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h)
> +{
> +	return 0;
> +}
> +
>  /* read the thread_struct into the current task */
>  int restore_thread(struct ckpt_ctx *ctx)
>  {
> diff --git a/checkpoint/process.c b/checkpoint/process.c
> index 4cce6f8..2ad79ee 100644
> --- a/checkpoint/process.c
> +++ b/checkpoint/process.c
> @@ -138,6 +138,8 @@ static int checkpoint_task_struct(struct ckpt_ctx *ctx, struct task_struct *t)
>  	h->exit_state = t->exit_state;
>  	h->exit_code = t->exit_code;
>  
> +	checkpoint_arch_thread(h, t);
> +
>  	if (t->exit_state) {
>  		/* zombie - skip remaining state */
>  		BUG_ON(t->exit_state != EXIT_ZOMBIE);
> @@ -504,6 +506,10 @@ static int restore_task_struct(struct ckpt_ctx *ctx)
>  	if (IS_ERR(h))
>  		return PTR_ERR(h);
>  
> +	ret = restore_arch_thread(ctx, h);
> +	if (ret)
> +		return ret;
> +
>  	ret = -EINVAL;
>  	if (h->state == TASK_DEAD) {
>  		if (h->exit_state != EXIT_ZOMBIE)
> diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
> index 550f6e8..343a166 100644
> --- a/include/linux/checkpoint.h
> +++ b/include/linux/checkpoint.h
> @@ -161,12 +161,18 @@ extern int restore_task(struct ckpt_ctx *ctx);
>  extern int pre_restore_task(void);
>  extern void post_restore_task(void);
>  
> +/* arch_thread flags */
> +#define CKPT_ARCH_32BIT		0x01
> +
>  /* arch hooks */
> +extern void checkpoint_arch_thread(struct ckpt_hdr_task *h,
> +				   struct task_struct *t);
>  extern int checkpoint_write_header_arch(struct ckpt_ctx *ctx);
>  extern int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t);
>  extern int checkpoint_cpu(struct ckpt_ctx *ctx, struct task_struct *t);
>  extern int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm);
>  
> +extern int restore_arch_thread(struct ckpt_ctx *ctx, struct ckpt_hdr_task *h);
>  extern int restore_read_header_arch(struct ckpt_ctx *ctx);
>  extern int restore_thread(struct ckpt_ctx *ctx);
>  extern int restore_cpu(struct ckpt_ctx *ctx);
> diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
> index 667b7aa..14976b2 100644
> --- a/include/linux/checkpoint_hdr.h
> +++ b/include/linux/checkpoint_hdr.h
> @@ -344,6 +344,7 @@ struct ckpt_hdr_task {
>  	__u32 compat_robust_futex_list; /* a compat __user ptr */
>  	__u32 robust_futex_head_len;
>  	__u64 robust_futex_list; /* a __user ptr */
> +	__u64 arch_flags;	 /* includes ARCH_32BIT */
>  } __attribute__((aligned(8)));
>  
>  /* Posix capabilities */

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH RFC] powerpc: catch 32/64bit mix
       [not found]     ` <4B0D7F96.6050100-eQaUEPhvms7ENvBUuze7eA@public.gmane.org>
@ 2009-11-25 19:16       ` Serge E. Hallyn
       [not found]         ` <20091125191617.GA11814-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Serge E. Hallyn @ 2009-11-25 19:16 UTC (permalink / raw)
  To: Oren Laadan; +Cc: Linux Containers

Quoting Oren Laadan (orenl-eQaUEPhvms7ENvBUuze7eA@public.gmane.org):
> 
> I can't recall a convincing reason why restore_{thread,cpu}() should
> run so late, or in particular after restore_task_objs().
> 
> I think the original motivation was to avoid the point-of-no-return
> at a very early stage. However this is only useful for self-restart.
> 
> If we ever want self-restart to fail gracefully should something go
> wrong, we should be prepared to undo any changes to the process -
> on the error path. While not beyond reach, it isn't a top priority.
> 
> Does calling restore_{thread,cpu}() earlier solve the problem ?

Yes, it does.

> BTW, this is also relevant for x86-64...

and also 31-bit s390

-serge

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH RFC] powerpc: catch 32/64bit mix
       [not found]         ` <20091125191617.GA11814-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2009-11-25 20:32           ` Oren Laadan
  0 siblings, 0 replies; 4+ messages in thread
From: Oren Laadan @ 2009-11-25 20:32 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: Linux Containers



Serge E. Hallyn wrote:
> Quoting Oren Laadan (orenl-eQaUEPhvms7ENvBUuze7eA@public.gmane.org):
>> I can't recall a convincing reason why restore_{thread,cpu}() should
>> run so late, or in particular after restore_task_objs().
>>
>> I think the original motivation was to avoid the point-of-no-return
>> at a very early stage. However this is only useful for self-restart.
>>
>> If we ever want self-restart to fail gracefully should something go
>> wrong, we should be prepared to undo any changes to the process -
>> on the error path. While not beyond reach, it isn't a top priority.
>>
>> Does calling restore_{thread,cpu}() earlier solve the problem ?
> 
> Yes, it does.
> 
>> BTW, this is also relevant for x86-64...
> 
> and also 31-bit s390

Excellent. Then I'll change the order for v19-rc2.

Thanks,

Oren.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-11-25 20:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-25 16:22 [PATCH RFC] powerpc: catch 32/64bit mix Serge E. Hallyn
     [not found] ` <20091125162250.GA9034-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2009-11-25 19:03   ` Oren Laadan
     [not found]     ` <4B0D7F96.6050100-eQaUEPhvms7ENvBUuze7eA@public.gmane.org>
2009-11-25 19:16       ` Serge E. Hallyn
     [not found]         ` <20091125191617.GA11814-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2009-11-25 20:32           ` Oren Laadan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.