diff options
-rw-r--r-- | arch/x86/include/asm/syscall.h | 14 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 21 | ||||
-rw-r--r-- | include/asm-generic/syscall.h | 8 |
3 files changed, 21 insertions, 22 deletions
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index d82f39bb7905..8d33bc5462d1 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Access to user system call parameters and results | 2 | * Access to user system call parameters and results |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Red Hat, Inc. All rights reserved. | 4 | * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. |
5 | * | 5 | * |
6 | * This copyrighted material is made available to anyone wishing to use, | 6 | * This copyrighted material is made available to anyone wishing to use, |
7 | * modify, copy, or redistribute it subject to the terms and conditions | 7 | * modify, copy, or redistribute it subject to the terms and conditions |
@@ -16,13 +16,13 @@ | |||
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | 18 | ||
19 | static inline long syscall_get_nr(struct task_struct *task, | 19 | /* |
20 | struct pt_regs *regs) | 20 | * Only the low 32 bits of orig_ax are meaningful, so we return int. |
21 | * This importantly ignores the high bits on 64-bit, so comparisons | ||
22 | * sign-extend the low 32 bits. | ||
23 | */ | ||
24 | static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) | ||
21 | { | 25 | { |
22 | /* | ||
23 | * We always sign-extend a -1 value being set here, | ||
24 | * so this is always either -1L or a syscall number. | ||
25 | */ | ||
26 | return regs->orig_ax; | 26 | return regs->orig_ax; |
27 | } | 27 | } |
28 | 28 | ||
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 8d7d5c9c1be3..7b058a2dc66a 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -325,16 +325,6 @@ static int putreg(struct task_struct *child, | |||
325 | return set_flags(child, value); | 325 | return set_flags(child, value); |
326 | 326 | ||
327 | #ifdef CONFIG_X86_64 | 327 | #ifdef CONFIG_X86_64 |
328 | /* | ||
329 | * Orig_ax is really just a flag with small positive and | ||
330 | * negative values, so make sure to always sign-extend it | ||
331 | * from 32 bits so that it works correctly regardless of | ||
332 | * whether we come from a 32-bit environment or not. | ||
333 | */ | ||
334 | case offsetof(struct user_regs_struct, orig_ax): | ||
335 | value = (long) (s32) value; | ||
336 | break; | ||
337 | |||
338 | case offsetof(struct user_regs_struct,fs_base): | 328 | case offsetof(struct user_regs_struct,fs_base): |
339 | if (value >= TASK_SIZE_OF(child)) | 329 | if (value >= TASK_SIZE_OF(child)) |
340 | return -EIO; | 330 | return -EIO; |
@@ -1126,10 +1116,15 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 value) | |||
1126 | 1116 | ||
1127 | case offsetof(struct user32, regs.orig_eax): | 1117 | case offsetof(struct user32, regs.orig_eax): |
1128 | /* | 1118 | /* |
1129 | * Sign-extend the value so that orig_eax = -1 | 1119 | * A 32-bit debugger setting orig_eax means to restore |
1130 | * causes (long)orig_ax < 0 tests to fire correctly. | 1120 | * the state of the task restarting a 32-bit syscall. |
1121 | * Make sure we interpret the -ERESTART* codes correctly | ||
1122 | * in case the task is not actually still sitting at the | ||
1123 | * exit from a 32-bit syscall with TS_COMPAT still set. | ||
1131 | */ | 1124 | */ |
1132 | regs->orig_ax = (long) (s32) value; | 1125 | regs->orig_ax = value; |
1126 | if (syscall_get_nr(child, regs) >= 0) | ||
1127 | task_thread_info(child)->status |= TS_COMPAT; | ||
1133 | break; | 1128 | break; |
1134 | 1129 | ||
1135 | case offsetof(struct user32, regs.eflags): | 1130 | case offsetof(struct user32, regs.eflags): |
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index ea8087b55ffc..5c122ae6bfa6 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Access to user system call parameters and results | 2 | * Access to user system call parameters and results |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Red Hat, Inc. All rights reserved. | 4 | * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. |
5 | * | 5 | * |
6 | * This copyrighted material is made available to anyone wishing to use, | 6 | * This copyrighted material is made available to anyone wishing to use, |
7 | * modify, copy, or redistribute it subject to the terms and conditions | 7 | * modify, copy, or redistribute it subject to the terms and conditions |
@@ -32,9 +32,13 @@ struct pt_regs; | |||
32 | * If @task is not executing a system call, i.e. it's blocked | 32 | * If @task is not executing a system call, i.e. it's blocked |
33 | * inside the kernel for a fault or signal, returns -1. | 33 | * inside the kernel for a fault or signal, returns -1. |
34 | * | 34 | * |
35 | * Note this returns int even on 64-bit machines. Only 32 bits of | ||
36 | * system call number can be meaningful. If the actual arch value | ||
37 | * is 64 bits, this truncates to 32 bits so 0xffffffff means -1. | ||
38 | * | ||
35 | * It's only valid to call this when @task is known to be blocked. | 39 | * It's only valid to call this when @task is known to be blocked. |
36 | */ | 40 | */ |
37 | long syscall_get_nr(struct task_struct *task, struct pt_regs *regs); | 41 | int syscall_get_nr(struct task_struct *task, struct pt_regs *regs); |
38 | 42 | ||
39 | /** | 43 | /** |
40 | * syscall_rollback - roll back registers after an aborted system call | 44 | * syscall_rollback - roll back registers after an aborted system call |