diff options
Diffstat (limited to 'arch/x86/ia32/ia32_signal.c')
| -rw-r--r-- | arch/x86/ia32/ia32_signal.c | 381 | 
1 files changed, 195 insertions, 186 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 9dabd00e980..588a7aa937e 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -33,8 +33,6 @@  #include <asm/sigframe.h>  #include <asm/sys_ia32.h> -#define DEBUG_SIG 0 -  #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))  #define FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \ @@ -46,78 +44,83 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);  int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)  { -	int err; +	int err = 0;  	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))  		return -EFAULT; -	/* If you change siginfo_t structure, please make sure that -	   this code is fixed accordingly. -	   It should never copy any pad contained in the structure -	   to avoid security leaks, but must copy the generic -	   3 ints plus the relevant union member.  */ -	err = __put_user(from->si_signo, &to->si_signo); -	err |= __put_user(from->si_errno, &to->si_errno); -	err |= __put_user((short)from->si_code, &to->si_code); +	put_user_try { +		/* If you change siginfo_t structure, please make sure that +		   this code is fixed accordingly. +		   It should never copy any pad contained in the structure +		   to avoid security leaks, but must copy the generic +		   3 ints plus the relevant union member.  */ +		put_user_ex(from->si_signo, &to->si_signo); +		put_user_ex(from->si_errno, &to->si_errno); +		put_user_ex((short)from->si_code, &to->si_code); -	if (from->si_code < 0) { -		err |= __put_user(from->si_pid, &to->si_pid); -		err |= __put_user(from->si_uid, &to->si_uid); -		err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr); -	} else { -		/* -		 * First 32bits of unions are always present: -		 * si_pid === si_band === si_tid === si_addr(LS half) -		 */ -		err |= __put_user(from->_sifields._pad[0], -				  &to->_sifields._pad[0]); -		switch (from->si_code >> 16) { -		case __SI_FAULT >> 16: -			break; -		case __SI_CHLD >> 16: -			err |= __put_user(from->si_utime, &to->si_utime); -			err |= __put_user(from->si_stime, &to->si_stime); -			err |= __put_user(from->si_status, &to->si_status); -			/* FALL THROUGH */ -		default: -		case __SI_KILL >> 16: -			err |= __put_user(from->si_uid, &to->si_uid); -			break; -		case __SI_POLL >> 16: -			err |= __put_user(from->si_fd, &to->si_fd); -			break; -		case __SI_TIMER >> 16: -			err |= __put_user(from->si_overrun, &to->si_overrun); -			err |= __put_user(ptr_to_compat(from->si_ptr), -					  &to->si_ptr); -			break; -			 /* This is not generated by the kernel as of now.  */ -		case __SI_RT >> 16: -		case __SI_MESGQ >> 16: -			err |= __put_user(from->si_uid, &to->si_uid); -			err |= __put_user(from->si_int, &to->si_int); -			break; +		if (from->si_code < 0) { +			put_user_ex(from->si_pid, &to->si_pid); +			put_user_ex(from->si_uid, &to->si_uid); +			put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr); +		} else { +			/* +			 * First 32bits of unions are always present: +			 * si_pid === si_band === si_tid === si_addr(LS half) +			 */ +			put_user_ex(from->_sifields._pad[0], +					  &to->_sifields._pad[0]); +			switch (from->si_code >> 16) { +			case __SI_FAULT >> 16: +				break; +			case __SI_CHLD >> 16: +				put_user_ex(from->si_utime, &to->si_utime); +				put_user_ex(from->si_stime, &to->si_stime); +				put_user_ex(from->si_status, &to->si_status); +				/* FALL THROUGH */ +			default: +			case __SI_KILL >> 16: +				put_user_ex(from->si_uid, &to->si_uid); +				break; +			case __SI_POLL >> 16: +				put_user_ex(from->si_fd, &to->si_fd); +				break; +			case __SI_TIMER >> 16: +				put_user_ex(from->si_overrun, &to->si_overrun); +				put_user_ex(ptr_to_compat(from->si_ptr), +					    &to->si_ptr); +				break; +				 /* This is not generated by the kernel as of now.  */ +			case __SI_RT >> 16: +			case __SI_MESGQ >> 16: +				put_user_ex(from->si_uid, &to->si_uid); +				put_user_ex(from->si_int, &to->si_int); +				break; +			}  		} -	} +	} put_user_catch(err); +  	return err;  }  int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)  { -	int err; +	int err = 0;  	u32 ptr32;  	if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))  		return -EFAULT; -	err = __get_user(to->si_signo, &from->si_signo); -	err |= __get_user(to->si_errno, &from->si_errno); -	err |= __get_user(to->si_code, &from->si_code); +	get_user_try { +		get_user_ex(to->si_signo, &from->si_signo); +		get_user_ex(to->si_errno, &from->si_errno); +		get_user_ex(to->si_code, &from->si_code); -	err |= __get_user(to->si_pid, &from->si_pid); -	err |= __get_user(to->si_uid, &from->si_uid); -	err |= __get_user(ptr32, &from->si_ptr); -	to->si_ptr = compat_ptr(ptr32); +		get_user_ex(to->si_pid, &from->si_pid); +		get_user_ex(to->si_uid, &from->si_uid); +		get_user_ex(ptr32, &from->si_ptr); +		to->si_ptr = compat_ptr(ptr32); +	} get_user_catch(err);  	return err;  } @@ -142,17 +145,23 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,  				  struct pt_regs *regs)  {  	stack_t uss, uoss; -	int ret; +	int ret, err = 0;  	mm_segment_t seg;  	if (uss_ptr) {  		u32 ptr;  		memset(&uss, 0, sizeof(stack_t)); -		if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) || -			    __get_user(ptr, &uss_ptr->ss_sp) || -			    __get_user(uss.ss_flags, &uss_ptr->ss_flags) || -			    __get_user(uss.ss_size, &uss_ptr->ss_size)) +		if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t))) +			return -EFAULT; + +		get_user_try { +			get_user_ex(ptr, &uss_ptr->ss_sp); +			get_user_ex(uss.ss_flags, &uss_ptr->ss_flags); +			get_user_ex(uss.ss_size, &uss_ptr->ss_size); +		} get_user_catch(err); + +		if (err)  			return -EFAULT;  		uss.ss_sp = compat_ptr(ptr);  	} @@ -161,10 +170,16 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,  	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);  	set_fs(seg);  	if (ret >= 0 && uoss_ptr)  { -		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) || -		    __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) || -		    __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) || -		    __put_user(uoss.ss_size, &uoss_ptr->ss_size)) +		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t))) +			return -EFAULT; + +		put_user_try { +			put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp); +			put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags); +			put_user_ex(uoss.ss_size, &uoss_ptr->ss_size); +		} put_user_catch(err); + +		if (err)  			ret = -EFAULT;  	}  	return ret; @@ -173,75 +188,78 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,  /*   * Do a signal return; undo the signal stack.   */ +#define loadsegment_gs(v)	load_gs_index(v) +#define loadsegment_fs(v)	loadsegment(fs, v) +#define loadsegment_ds(v)	loadsegment(ds, v) +#define loadsegment_es(v)	loadsegment(es, v) + +#define get_user_seg(seg)	({ unsigned int v; savesegment(seg, v); v; }) +#define set_user_seg(seg, v)	loadsegment_##seg(v) +  #define COPY(x)			{		\ -	err |= __get_user(regs->x, &sc->x);	\ +	get_user_ex(regs->x, &sc->x);		\  } -#define COPY_SEG_CPL3(seg)	{			\ -		unsigned short tmp;			\ -		err |= __get_user(tmp, &sc->seg);	\ -		regs->seg = tmp | 3;			\ -} +#define GET_SEG(seg)		({			\ +	unsigned short tmp;				\ +	get_user_ex(tmp, &sc->seg);			\ +	tmp;						\ +}) + +#define COPY_SEG_CPL3(seg)	do {			\ +	regs->seg = GET_SEG(seg) | 3;			\ +} while (0)  #define RELOAD_SEG(seg)		{		\ -	unsigned int cur, pre;			\ -	err |= __get_user(pre, &sc->seg);	\ -	savesegment(seg, cur);			\ +	unsigned int pre = GET_SEG(seg);	\ +	unsigned int cur = get_user_seg(seg);	\  	pre |= 3;				\  	if (pre != cur)				\ -		loadsegment(seg, pre);		\ +		set_user_seg(seg, pre);		\  }  static int ia32_restore_sigcontext(struct pt_regs *regs,  				   struct sigcontext_ia32 __user *sc,  				   unsigned int *pax)  { -	unsigned int tmpflags, gs, oldgs, err = 0; +	unsigned int tmpflags, err = 0;  	void __user *buf;  	u32 tmp;  	/* Always make any pending restarted system calls return -EINTR */  	current_thread_info()->restart_block.fn = do_no_restart_syscall; -#if DEBUG_SIG -	printk(KERN_DEBUG "SIG restore_sigcontext: " -	       "sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n", -	       sc, sc->err, sc->ip, sc->cs, sc->flags); -#endif - -	/* -	 * Reload fs and gs if they have changed in the signal -	 * handler.  This does not handle long fs/gs base changes in -	 * the handler, but does not clobber them at least in the -	 * normal case. -	 */ -	err |= __get_user(gs, &sc->gs); -	gs |= 3; -	savesegment(gs, oldgs); -	if (gs != oldgs) -		load_gs_index(gs); +	get_user_try { +		/* +		 * Reload fs and gs if they have changed in the signal +		 * handler.  This does not handle long fs/gs base changes in +		 * the handler, but does not clobber them at least in the +		 * normal case. +		 */ +		RELOAD_SEG(gs); +		RELOAD_SEG(fs); +		RELOAD_SEG(ds); +		RELOAD_SEG(es); -	RELOAD_SEG(fs); -	RELOAD_SEG(ds); -	RELOAD_SEG(es); +		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); +		COPY(dx); COPY(cx); COPY(ip); +		/* Don't touch extended registers */ -	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); -	COPY(dx); COPY(cx); COPY(ip); -	/* Don't touch extended registers */ +		COPY_SEG_CPL3(cs); +		COPY_SEG_CPL3(ss); -	COPY_SEG_CPL3(cs); -	COPY_SEG_CPL3(ss); +		get_user_ex(tmpflags, &sc->flags); +		regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); +		/* disable syscall checks */ +		regs->orig_ax = -1; -	err |= __get_user(tmpflags, &sc->flags); -	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); -	/* disable syscall checks */ -	regs->orig_ax = -1; +		get_user_ex(tmp, &sc->fpstate); +		buf = compat_ptr(tmp); +		err |= restore_i387_xstate_ia32(buf); -	err |= __get_user(tmp, &sc->fpstate); -	buf = compat_ptr(tmp); -	err |= restore_i387_xstate_ia32(buf); +		get_user_ex(*pax, &sc->ax); +	} get_user_catch(err); -	err |= __get_user(*pax, &sc->ax);  	return err;  } @@ -317,38 +335,36 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,  				 void __user *fpstate,  				 struct pt_regs *regs, unsigned int mask)  { -	int tmp, err = 0; +	int err = 0; -	savesegment(gs, tmp); -	err |= __put_user(tmp, (unsigned int __user *)&sc->gs); -	savesegment(fs, tmp); -	err |= __put_user(tmp, (unsigned int __user *)&sc->fs); -	savesegment(ds, tmp); -	err |= __put_user(tmp, (unsigned int __user *)&sc->ds); -	savesegment(es, tmp); -	err |= __put_user(tmp, (unsigned int __user *)&sc->es); +	put_user_try { +		put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs); +		put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs); +		put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds); +		put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es); -	err |= __put_user(regs->di, &sc->di); -	err |= __put_user(regs->si, &sc->si); -	err |= __put_user(regs->bp, &sc->bp); -	err |= __put_user(regs->sp, &sc->sp); -	err |= __put_user(regs->bx, &sc->bx); -	err |= __put_user(regs->dx, &sc->dx); -	err |= __put_user(regs->cx, &sc->cx); -	err |= __put_user(regs->ax, &sc->ax); -	err |= __put_user(current->thread.trap_no, &sc->trapno); -	err |= __put_user(current->thread.error_code, &sc->err); -	err |= __put_user(regs->ip, &sc->ip); -	err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); -	err |= __put_user(regs->flags, &sc->flags); -	err |= __put_user(regs->sp, &sc->sp_at_signal); -	err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); +		put_user_ex(regs->di, &sc->di); +		put_user_ex(regs->si, &sc->si); +		put_user_ex(regs->bp, &sc->bp); +		put_user_ex(regs->sp, &sc->sp); +		put_user_ex(regs->bx, &sc->bx); +		put_user_ex(regs->dx, &sc->dx); +		put_user_ex(regs->cx, &sc->cx); +		put_user_ex(regs->ax, &sc->ax); +		put_user_ex(current->thread.trap_no, &sc->trapno); +		put_user_ex(current->thread.error_code, &sc->err); +		put_user_ex(regs->ip, &sc->ip); +		put_user_ex(regs->cs, (unsigned int __user *)&sc->cs); +		put_user_ex(regs->flags, &sc->flags); +		put_user_ex(regs->sp, &sc->sp_at_signal); +		put_user_ex(regs->ss, (unsigned int __user *)&sc->ss); -	err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate); +		put_user_ex(ptr_to_compat(fpstate), &sc->fpstate); -	/* non-iBCS2 extensions.. */ -	err |= __put_user(mask, &sc->oldmask); -	err |= __put_user(current->thread.cr2, &sc->cr2); +		/* non-iBCS2 extensions.. */ +		put_user_ex(mask, &sc->oldmask); +		put_user_ex(current->thread.cr2, &sc->cr2); +	} put_user_catch(err);  	return err;  } @@ -437,13 +453,17 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,  		else  			restorer = &frame->retcode;  	} -	err |= __put_user(ptr_to_compat(restorer), &frame->pretcode); -	/* -	 * These are actually not used anymore, but left because some -	 * gdb versions depend on them as a marker. -	 */ -	err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode); +	put_user_try { +		put_user_ex(ptr_to_compat(restorer), &frame->pretcode); + +		/* +		 * These are actually not used anymore, but left because some +		 * gdb versions depend on them as a marker. +		 */ +		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode); +	} put_user_catch(err); +  	if (err)  		return -EFAULT; @@ -462,11 +482,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,  	regs->cs = __USER32_CS;  	regs->ss = __USER32_DS; -#if DEBUG_SIG -	printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n", -	       current->comm, current->pid, frame, regs->ip, frame->pretcode); -#endif -  	return 0;  } @@ -496,41 +511,40 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))  		return -EFAULT; -	err |= __put_user(sig, &frame->sig); -	err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); -	err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); -	err |= copy_siginfo_to_user32(&frame->info, info); -	if (err) -		return -EFAULT; +	put_user_try { +		put_user_ex(sig, &frame->sig); +		put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo); +		put_user_ex(ptr_to_compat(&frame->uc), &frame->puc); +		err |= copy_siginfo_to_user32(&frame->info, info); -	/* Create the ucontext.  */ -	if (cpu_has_xsave) -		err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); -	else -		err |= __put_user(0, &frame->uc.uc_flags); -	err |= __put_user(0, &frame->uc.uc_link); -	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->sp), -			  &frame->uc.uc_stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); -	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, -				     regs, set->sig[0]); -	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); -	if (err) -		return -EFAULT; +		/* Create the ucontext.  */ +		if (cpu_has_xsave) +			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); +		else +			put_user_ex(0, &frame->uc.uc_flags); +		put_user_ex(0, &frame->uc.uc_link); +		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); +		put_user_ex(sas_ss_flags(regs->sp), +			    &frame->uc.uc_stack.ss_flags); +		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); +		err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, +					     regs, set->sig[0]); +		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); -	if (ka->sa.sa_flags & SA_RESTORER) -		restorer = ka->sa.sa_restorer; -	else -		restorer = VDSO32_SYMBOL(current->mm->context.vdso, -					 rt_sigreturn); -	err |= __put_user(ptr_to_compat(restorer), &frame->pretcode); +		if (ka->sa.sa_flags & SA_RESTORER) +			restorer = ka->sa.sa_restorer; +		else +			restorer = VDSO32_SYMBOL(current->mm->context.vdso, +						 rt_sigreturn); +		put_user_ex(ptr_to_compat(restorer), &frame->pretcode); + +		/* +		 * Not actually used anymore, but left because some gdb +		 * versions need it. +		 */ +		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode); +	} put_user_catch(err); -	/* -	 * Not actually used anymore, but left because some gdb -	 * versions need it. -	 */ -	err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);  	if (err)  		return -EFAULT; @@ -549,10 +563,5 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	regs->cs = __USER32_CS;  	regs->ss = __USER32_DS; -#if DEBUG_SIG -	printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n", -	       current->comm, current->pid, frame, regs->ip, frame->pretcode); -#endif -  	return 0;  }  |