important bug fix
PATCH 1/1 important bug fix
Yesterday, I discovered that the ia32 subsystem is missing support for the regular sigsuspend() system call (newer versions of glibc use rt_sigsuspend()). When looking at the existing ia32 rt_sigsuspend() code, I realized that it was wrong and shouldn't work at all. Turns the reason it worked was because there was a missing access_ok() in sys_rt_sigsuspend(). Ouch! This is a serious bug as it creates a security hole. The patch below fixes this problem and updates the ia32 subsystem accordingly.
Anyhow interested in writing (or enhancing an existing) kernel validation suite which will verify that all system calls return -EFAULT for illegal pointer arguments? Bugs like these could be caught very easily...
--david
arch/ia64/ia32/ia32_entry.S +37 -25
@@ -48,31 +48,43 @@ br.ret.sptk.many rp END(ia32_clone) - // - // Get possibly unaligned sigmask argument into an aligned - // kernel buffer -GLOBAL_ENTRY(ia32_rt_sigsuspend) - // We'll cheat and not do an alloc here since we are ultimately - // going to do a simple branch to the IA64 sys_rt_sigsuspend. - // r32 is still the first argument which is the signal mask. - // We copy this 4-byte aligned value to an 8-byte aligned buffer - // in the task structure and then jump to the IA64 code. - zxt4 r32=r32 - ;; - EX(.Lfail, ld4 r2=[r32],4) // load low part of sigmask - ;; - EX(.Lfail, ld4 r3=[r32]) // load high part of sigmask - adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13 - ;; - st8 [r32]=r2 - adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13 +ENTRY(sys32_rt_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in0 // mask + mov out1=in1 // sigsetsize + mov out2=sp // out2 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" ;; + .body + br.call.sptk.many rp=ia32_rt_sigsuspend +1: .restore sp + adds sp,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_rt_sigsuspend) - st4 [r10]=r3 - br.cond.sptk.many sys_rt_sigsuspend - -.Lfail: br.ret.sptk.many rp // failed to read sigmask -END(ia32_rt_sigsuspend) +ENTRY(sys32_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc r2=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in0 // mask + mov out1=4 // sigsetsize + ;; + mov out2=sp // out2 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" + .body + br.call.sptk.many rp=ia32_rt_sigsuspend +1: .restore sp + adds sp,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_sigsuspend) GLOBAL_ENTRY(ia32_ret_from_clone) PT_REGS_UNWIND_INFO(0)
@@ -236,7 +248,7 @@ data8 sys32_ni_syscall data8 sys_setreuid /* 16-bit version */ /* 70 */ data8 sys_setregid /* 16-bit version */ - data8 sys32_ni_syscall + data8 sys32_sigsuspend data8 sys32_sigpending data8 sys_sethostname data8 sys32_setrlimit /* 75 */
@@ -343,7 +355,7 @@ data8 sys_rt_sigpending data8 sys32_rt_sigtimedwait data8 sys32_rt_sigqueueinfo - data8 ia32_rt_sigsuspend + data8 sys32_rt_sigsuspend data8 sys32_pread /* 180 */ data8 sys32_pwrite data8 sys_chown /* 16-bit version */
arch/ia64/ia32/ia32_signal.c +217 -0
230 lines not on this page · raw message
arch/ia64/ia32/sys_ia32.c +0 -181
193 lines not on this page · raw message
arch/ia64/kernel/sigframe.h +6 -0
@@ -1,3 +1,9 @@ +struct sigscratch { +unsigned long scratch_unat;/* ar.unat for the general registers saved in pt */ +unsigned long pad; +struct pt_regs pt; +}; +struct sigframe {/* * Place signal handler args where user-level unwinder can find them easily.
arch/ia64/kernel/signal.c +8 -16
@@ -2,7 +2,7 @@* Architecture-specific signal handling support. * * Copyright (C) 1999-2001 Hewlett-Packard Co -* Copyright (C) 1999-2001 David Mosberger-Tang <[email protected]> +* David Mosberger-Tang <[email protected]> * * Derived from i386 and Alpha versions. */
@@ -39,12 +39,6 @@# define GET_SIGSET (k,u) __get_user((k)->sig[0], &(u)->sig[0])#endif -struct sigscratch { -unsigned long scratch_unat;/* ar.unat for the general registers saved in pt */ -unsigned long pad; -struct pt_regs pt; -}; -extern long ia64_do_signal (sigset_t *,struct sigscratch *,long );/* forward decl */ long
@@ -55,6 +49,10 @@/* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize !=sizeof (sigset_t))return -EINVAL ; + +if (!access_ok (VERIFY_READ , uset, sigsetsize)) +return -EFAULT ; +if (GET_SIGSET (&set, uset))return -EFAULT ;
@@ -73,15 +71,9 @@* pre-set the correct error code here to ensure that the right values * get saved in sigcontext by ia64_do_signal. */ -#ifdef CONFIG_IA32_SUPPORT -if (IS_IA32_PROCESS (&scr->pt)) { - scr->pt.r8 = -EINTR ; - } else -#endif - { - scr->pt.r8 =EINTR ; - scr->pt.r10 =-1 ; - } + scr->pt.r8 =EINTR ; + scr->pt.r10 =-1 ; +while (1 ) { current->state =TASK_INTERRUPTIBLE ;schedule ();
include/asm-ia64/ia32.h +5 -0
@@ -39,6 +39,11 @@#define IA32_CLOCKS_PER_SEC 100/* Cast in stone for IA32 Linux */ #define IA32_TICK (tick) ((unsigned long long)(tick) * IA32_CLOCKS_PER_SEC / CLOCKS_PER_SEC) +struct timespec32 { +int tv_sec; +int tv_nsec; +}; +/* fcntl.h */ struct flock32 {short l_type;
include/asm-ia64/processor.h +1 -4
@@ -347,10 +344,7 @@__u64 ssd;/* IA32 stack selector descriptor */ __u64 tssd;/* IA32 TSS descriptor */ __u64 old_iob;/* old IOBase value */ -union { -__u64 sigmask;/* aligned mask for sigsuspend scall */ - } un; -# define INIT_THREAD_IA32 0, 0, 0x17800000037fULL, 0, 0, 0, 0, 0, 0, {0}, +# define INIT_THREAD_IA32 0, 0, 0x17800000037fULL, 0, 0, 0, 0, 0, 0,#else # define INIT_THREAD_IA32 #endif /* CONFIG_IA32_SUPPORT */