powerpc: catch 32/64bit mix
RFC PATCH 1/1 powerpc: catch 32/64bit mix
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.
--- 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(-)
arch/powerpc/mm/checkpoint.c +30 -0
@@ -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) {
arch/s390/mm/checkpoint.c +10 -0
@@ -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 ;
arch/x86/mm/checkpoint.c +10 -0
@@ -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) {
checkpoint/process.c +6 -0
@@ -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 )
include/linux/checkpoint.h +6 -0
@@ -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);
include/linux/checkpoint_hdr.h +1 -0
@@ -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 */
Signature · 1 line
1.6.2.3
A message that is not in the archive (sent off-list or not yet received): 20091125162250.GA9034-r/[email protected]
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.
Quoted 192 lines · Serge E. Hallyn
The arch-specific
restore_thread()andrestore_cpu()are called after restore_task_obj()s. This means that when a 32-bit task callssys_restart()with a 64-bit image, we'll be reloading memory mappings before those are called, and get a 'mysterious'-EINVALfor trying to map libc into an area >TASK_SIZE.This patch just adds a set of arch-specific flags to the
cpu_hdr_taskstruct. s390 can use this to noteTIF_31BIT, and powerpc uses it to markTIF_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 oneIf we keep this patch, then we'll want to drop
bitness_testfromrestore_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/[email protected]>--- 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(-)arch/powerpc/mm/checkpoint.c +30
-0@@ -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) {arch/s390/mm/checkpoint.c +10
-0@@ -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 ;arch/x86/mm/checkpoint.c +10
-0@@ -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) {checkpoint/process.c +6
-0@@ -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 )include/linux/checkpoint.h +6
-0@@ -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);include/linux/checkpoint_hdr.h +1
-0@@ -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 */
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 4 lines · Oren Laadan
I can't recall a convincing reason why restore_{thread,cpu}() should run so late, or in particular after
restore_task_objs().
Quoted 8 lines
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.
Quoted 1 line
BTW, this is also relevant for x86-64...
and also 31-bit s390
-serge
A message that is not in the archive (sent off-list or not yet received): 20091125191617.GA11814-r/[email protected]
Quoted 11 lines · Serge E. Hallyn
Quoted 10 lines · Oren Laadan
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.
Quoted 7 lines
Quoted 1 line
Does calling restore_{thread,cpu}() earlier solve the problem ?
Yes, it does.
Quoted 1 line
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.