aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/entry/common.c6
-rw-r--r--arch/x86/entry/syscalls/syscall_32.tbl2
-rw-r--r--arch/x86/entry/vdso/vdso2c.h6
-rw-r--r--arch/x86/include/asm/syscall.h5
-rw-r--r--arch/x86/include/asm/thread_info.h3
-rw-r--r--arch/x86/kernel/ptrace.c15
-rw-r--r--arch/x86/kernel/signal.c26
7 files changed, 49 insertions, 14 deletions
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index a1e71d431fed..1433f6b4607d 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -204,8 +204,12 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
204 * handling, because syscall restart has a fixup for compat 204 * handling, because syscall restart has a fixup for compat
205 * syscalls. The fixup is exercised by the ptrace_syscall_32 205 * syscalls. The fixup is exercised by the ptrace_syscall_32
206 * selftest. 206 * selftest.
207 *
208 * We also need to clear TS_REGS_POKED_I386: the 32-bit tracer
209 * special case only applies after poking regs and before the
210 * very next return to user mode.
207 */ 211 */
208 ti->status &= ~TS_COMPAT; 212 ti->status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
209#endif 213#endif
210 214
211 user_enter_irqoff(); 215 user_enter_irqoff();
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 4cddd17153fb..f848572169ea 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -294,7 +294,7 @@
294# 285 sys_setaltroot 294# 285 sys_setaltroot
295286 i386 add_key sys_add_key 295286 i386 add_key sys_add_key
296287 i386 request_key sys_request_key 296287 i386 request_key sys_request_key
297288 i386 keyctl sys_keyctl 297288 i386 keyctl sys_keyctl compat_sys_keyctl
298289 i386 ioprio_set sys_ioprio_set 298289 i386 ioprio_set sys_ioprio_set
299290 i386 ioprio_get sys_ioprio_get 299290 i386 ioprio_get sys_ioprio_get
300291 i386 inotify_init sys_inotify_init 300291 i386 inotify_init sys_inotify_init
diff --git a/arch/x86/entry/vdso/vdso2c.h b/arch/x86/entry/vdso/vdso2c.h
index 63a03bb91497..4f741192846d 100644
--- a/arch/x86/entry/vdso/vdso2c.h
+++ b/arch/x86/entry/vdso/vdso2c.h
@@ -22,6 +22,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
22 22
23 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_LE(&hdr->e_phoff)); 23 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_LE(&hdr->e_phoff));
24 24
25 if (hdr->e_type != ET_DYN)
26 fail("input is not a shared object\n");
27
25 /* Walk the segment table. */ 28 /* Walk the segment table. */
26 for (i = 0; i < GET_LE(&hdr->e_phnum); i++) { 29 for (i = 0; i < GET_LE(&hdr->e_phnum); i++) {
27 if (GET_LE(&pt[i].p_type) == PT_LOAD) { 30 if (GET_LE(&pt[i].p_type) == PT_LOAD) {
@@ -49,6 +52,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
49 if (stripped_len < load_size) 52 if (stripped_len < load_size)
50 fail("stripped input is too short\n"); 53 fail("stripped input is too short\n");
51 54
55 if (!dyn)
56 fail("input has no PT_DYNAMIC section -- your toolchain is buggy\n");
57
52 /* Walk the dynamic table */ 58 /* Walk the dynamic table */
53 for (i = 0; dyn + i < dyn_end && 59 for (i = 0; dyn + i < dyn_end &&
54 GET_LE(&dyn[i].d_tag) != DT_NULL; i++) { 60 GET_LE(&dyn[i].d_tag) != DT_NULL; i++) {
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index 999b7cd2e78c..4e23dd15c661 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -60,7 +60,7 @@ static inline long syscall_get_error(struct task_struct *task,
60 * TS_COMPAT is set for 32-bit syscall entries and then 60 * TS_COMPAT is set for 32-bit syscall entries and then
61 * remains set until we return to user mode. 61 * remains set until we return to user mode.
62 */ 62 */
63 if (task_thread_info(task)->status & TS_COMPAT) 63 if (task_thread_info(task)->status & (TS_COMPAT|TS_I386_REGS_POKED))
64 /* 64 /*
65 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 65 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
66 * and will match correctly in comparisons. 66 * and will match correctly in comparisons.
@@ -239,9 +239,6 @@ static inline int syscall_get_arch(void)
239 * TS_COMPAT is set for 32-bit syscall entry and then 239 * TS_COMPAT is set for 32-bit syscall entry and then
240 * remains set until we return to user mode. 240 * remains set until we return to user mode.
241 * 241 *
242 * TIF_IA32 tasks should always have TS_COMPAT set at
243 * system call time.
244 *
245 * x32 tasks should be considered AUDIT_ARCH_X86_64. 242 * x32 tasks should be considered AUDIT_ARCH_X86_64.
246 */ 243 */
247 if (task_thread_info(current)->status & TS_COMPAT) 244 if (task_thread_info(current)->status & TS_COMPAT)
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index b45ffdda3549..84b59846154a 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -219,6 +219,9 @@ static inline unsigned long current_stack_pointer(void)
219 * have to worry about atomic accesses. 219 * have to worry about atomic accesses.
220 */ 220 */
221#define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/ 221#define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/
222#ifdef CONFIG_COMPAT
223#define TS_I386_REGS_POKED 0x0004 /* regs poked by 32-bit ptracer */
224#endif
222 225
223#ifndef __ASSEMBLY__ 226#ifndef __ASSEMBLY__
224 227
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 600edd225e81..f79576a541ff 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -923,15 +923,18 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 value)
923 923
924 case offsetof(struct user32, regs.orig_eax): 924 case offsetof(struct user32, regs.orig_eax):
925 /* 925 /*
926 * A 32-bit debugger setting orig_eax means to restore 926 * Warning: bizarre corner case fixup here. A 32-bit
927 * the state of the task restarting a 32-bit syscall. 927 * debugger setting orig_eax to -1 wants to disable
928 * Make sure we interpret the -ERESTART* codes correctly 928 * syscall restart. Make sure that the syscall
929 * in case the task is not actually still sitting at the 929 * restart code sign-extends orig_ax. Also make sure
930 * exit from a 32-bit syscall with TS_COMPAT still set. 930 * we interpret the -ERESTART* codes correctly if
931 * loaded into regs->ax in case the task is not
932 * actually still sitting at the exit from a 32-bit
933 * syscall with TS_COMPAT still set.
931 */ 934 */
932 regs->orig_ax = value; 935 regs->orig_ax = value;
933 if (syscall_get_nr(child, regs) >= 0) 936 if (syscall_get_nr(child, regs) >= 0)
934 task_thread_info(child)->status |= TS_COMPAT; 937 task_thread_info(child)->status |= TS_I386_REGS_POKED;
935 break; 938 break;
936 939
937 case offsetof(struct user32, regs.eflags): 940 case offsetof(struct user32, regs.eflags):
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 99f285b512db..04cb3212db2d 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -760,8 +760,30 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
760 760
761static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs) 761static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
762{ 762{
763#ifdef CONFIG_X86_64 763 /*
764 if (in_ia32_syscall()) 764 * This function is fundamentally broken as currently
765 * implemented.
766 *
767 * The idea is that we want to trigger a call to the
768 * restart_block() syscall and that we want in_ia32_syscall(),
769 * in_x32_syscall(), etc. to match whatever they were in the
770 * syscall being restarted. We assume that the syscall
771 * instruction at (regs->ip - 2) matches whatever syscall
772 * instruction we used to enter in the first place.
773 *
774 * The problem is that we can get here when ptrace pokes
775 * syscall-like values into regs even if we're not in a syscall
776 * at all.
777 *
778 * For now, we maintain historical behavior and guess based on
779 * stored state. We could do better by saving the actual
780 * syscall arch in restart_block or (with caveats on x32) by
781 * checking if regs->ip points to 'int $0x80'. The current
782 * behavior is incorrect if a tracer has a different bitness
783 * than the tracee.
784 */
785#ifdef CONFIG_IA32_EMULATION
786 if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
765 return __NR_ia32_restart_syscall; 787 return __NR_ia32_restart_syscall;
766#endif 788#endif
767#ifdef CONFIG_X86_X32_ABI 789#ifdef CONFIG_X86_X32_ABI