ia32_signal.c 14.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *  linux/arch/x86_64/ia32/ia32_signal.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
 *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
 *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
 */

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/compat.h>
21
#include <linux/binfmts.h>
L
Linus Torvalds 已提交
22 23 24
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
25
#include <asm/fpu-internal.h>
L
Linus Torvalds 已提交
26 27 28 29 30
#include <asm/ptrace.h>
#include <asm/ia32_unistd.h>
#include <asm/user32.h>
#include <asm/sigcontext32.h>
#include <asm/proto.h>
31
#include <asm/vdso.h>
32
#include <asm/sigframe.h>
33
#include <asm/sighandling.h>
34
#include <asm/sys_ia32.h>
35

36
#define FIX_EFLAGS	__FIX_EFLAGS
L
Linus Torvalds 已提交
37 38 39

int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
40
	int err = 0;
41
	bool ia32 = is_ia32_task();
42 43

	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
L
Linus Torvalds 已提交
44 45
		return -EFAULT;

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	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) {
			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:
71 72 73 74 75 76 77
				if (ia32) {
					put_user_ex(from->si_utime, &to->si_utime);
					put_user_ex(from->si_stime, &to->si_stime);
				} else {
					put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
					put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
				}
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
				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;
			}
L
Linus Torvalds 已提交
99
		}
100 101
	} put_user_catch(err);

L
Linus Torvalds 已提交
102 103 104 105 106
	return err;
}

int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
107
	int err = 0;
L
Linus Torvalds 已提交
108
	u32 ptr32;
109 110

	if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
L
Linus Torvalds 已提交
111 112
		return -EFAULT;

113 114 115 116
	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);
L
Linus Torvalds 已提交
117

118 119 120 121 122
		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);
L
Linus Torvalds 已提交
123 124 125 126

	return err;
}

127
asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
L
Linus Torvalds 已提交
128
{
129 130
	sigset_t blocked;

131
	current->saved_sigmask = current->blocked;
132 133 134 135

	mask &= _BLOCKABLE;
	siginitset(&blocked, mask);
	set_current_blocked(&blocked);
L
Linus Torvalds 已提交
136

137 138
	current->state = TASK_INTERRUPTIBLE;
	schedule();
139

140
	set_restore_sigmask();
141
	return -ERESTARTNOHAND;
L
Linus Torvalds 已提交
142 143
}

144 145 146
asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
				  stack_ia32_t __user *uoss_ptr,
				  struct pt_regs *regs)
L
Linus Torvalds 已提交
147
{
148
	stack_t uss, uoss;
149
	int ret, err = 0;
150 151 152
	mm_segment_t seg;

	if (uss_ptr) {
L
Linus Torvalds 已提交
153
		u32 ptr;
154 155

		memset(&uss, 0, sizeof(stack_t));
156 157 158 159 160 161 162 163 164 165
		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)
L
Linus Torvalds 已提交
166 167 168
			return -EFAULT;
		uss.ss_sp = compat_ptr(ptr);
	}
169 170
	seg = get_fs();
	set_fs(KERNEL_DS);
171
	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
172
	set_fs(seg);
L
Linus Torvalds 已提交
173
	if (ret >= 0 && uoss_ptr)  {
174 175 176 177 178 179 180 181 182 183
		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)
L
Linus Torvalds 已提交
184
			ret = -EFAULT;
185 186
	}
	return ret;
L
Linus Torvalds 已提交
187 188 189 190 191
}

/*
 * Do a signal return; undo the signal stack.
 */
192 193 194 195 196 197 198 199
#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)

200
#define COPY(x)			{		\
201
	get_user_ex(regs->x, &sc->x);		\
L
Linus Torvalds 已提交
202 203
}

204 205 206 207 208 209 210 211 212
#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)
L
Linus Torvalds 已提交
213

214
#define RELOAD_SEG(seg)		{		\
215 216
	unsigned int pre = GET_SEG(seg);	\
	unsigned int cur = get_user_seg(seg);	\
217 218
	pre |= 3;				\
	if (pre != cur)				\
219
		set_user_seg(seg, pre);		\
220
}
221 222 223

static int ia32_restore_sigcontext(struct pt_regs *regs,
				   struct sigcontext_ia32 __user *sc,
224
				   unsigned int *pax)
225
{
226
	unsigned int tmpflags, err = 0;
227
	void __user *buf;
228 229 230 231 232
	u32 tmp;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

233 234 235 236 237 238 239
	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.
		 */
240
		RELOAD_SEG(gs);
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
		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_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;

		get_user_ex(tmp, &sc->fpstate);
		buf = compat_ptr(tmp);
		err |= restore_i387_xstate_ia32(buf);

		get_user_ex(*pax, &sc->ax);
	} get_user_catch(err);

L
Linus Torvalds 已提交
264 265 266 267 268
	return err;
}

asmlinkage long sys32_sigreturn(struct pt_regs *regs)
{
269
	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
L
Linus Torvalds 已提交
270
	sigset_t set;
271
	unsigned int ax;
L
Linus Torvalds 已提交
272 273 274 275 276

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__get_user(set.sig[0], &frame->sc.oldmask)
	    || (_COMPAT_NSIG_WORDS > 1
277 278
		&& __copy_from_user((((char *) &set.sig) + 4),
				    &frame->extramask,
L
Linus Torvalds 已提交
279 280 281 282
				    sizeof(frame->extramask))))
		goto badframe;

	sigdelsetmask(&set, ~_BLOCKABLE);
283
	set_current_blocked(&set);
284

285
	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
L
Linus Torvalds 已提交
286
		goto badframe;
287
	return ax;
L
Linus Torvalds 已提交
288 289 290 291

badframe:
	signal_fault(regs, frame, "32bit sigreturn");
	return 0;
292
}
L
Linus Torvalds 已提交
293 294 295

asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
{
296
	struct rt_sigframe_ia32 __user *frame;
L
Linus Torvalds 已提交
297
	sigset_t set;
298
	unsigned int ax;
L
Linus Torvalds 已提交
299 300
	struct pt_regs tregs;

301
	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
L
Linus Torvalds 已提交
302 303 304 305 306 307 308

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
		goto badframe;

	sigdelsetmask(&set, ~_BLOCKABLE);
309
	set_current_blocked(&set);
310

311
	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
L
Linus Torvalds 已提交
312 313 314 315 316 317
		goto badframe;

	tregs = *regs;
	if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
		goto badframe;

318
	return ax;
L
Linus Torvalds 已提交
319 320

badframe:
321
	signal_fault(regs, frame, "32bit rt sigreturn");
L
Linus Torvalds 已提交
322
	return 0;
323
}
L
Linus Torvalds 已提交
324 325 326 327 328

/*
 * Set up a signal frame.
 */

329
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
330
				 void __user *fpstate,
331
				 struct pt_regs *regs, unsigned int mask)
L
Linus Torvalds 已提交
332
{
333
	int err = 0;
L
Linus Torvalds 已提交
334

335
	put_user_try {
336 337 338 339
		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);
340 341 342 343 344 345 346 347 348

		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);
349
		put_user_ex(current->thread.trap_nr, &sc->trapno);
350 351 352 353 354 355 356 357 358 359 360 361 362
		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);

		put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);

		/* non-iBCS2 extensions.. */
		put_user_ex(mask, &sc->oldmask);
		put_user_ex(current->thread.cr2, &sc->cr2);
	} put_user_catch(err);
L
Linus Torvalds 已提交
363 364 365 366 367 368 369

	return err;
}

/*
 * Determine which stack to use..
 */
370
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
371
				 size_t frame_size,
372
				 void **fpstate)
L
Linus Torvalds 已提交
373
{
374
	unsigned long sp;
L
Linus Torvalds 已提交
375 376

	/* Default to using normal stack */
377
	sp = regs->sp;
L
Linus Torvalds 已提交
378 379 380

	/* This is the X/Open sanctioned signal stack switching.  */
	if (ka->sa.sa_flags & SA_ONSTACK) {
381 382
		if (sas_ss_flags(sp) == 0)
			sp = current->sas_ss_sp + current->sas_ss_size;
L
Linus Torvalds 已提交
383 384 385
	}

	/* This is the legacy signal stack switching. */
386
	else if ((regs->ss & 0xffff) != __USER32_DS &&
L
Linus Torvalds 已提交
387
		!(ka->sa.sa_flags & SA_RESTORER) &&
388
		 ka->sa.sa_restorer)
389
		sp = (unsigned long) ka->sa.sa_restorer;
L
Linus Torvalds 已提交
390

391 392 393
	if (used_math()) {
		sp = sp - sig_xstate_ia32_size;
		*fpstate = (struct _fpstate_ia32 *) sp;
394 395
		if (save_i387_xstate_ia32(*fpstate) < 0)
			return (void __user *) -1L;
396 397
	}

398
	sp -= frame_size;
399 400
	/* Align the stack pointer according to the i386 ABI,
	 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
401 402
	sp = ((sp + 4) & -16ul) - 4;
	return (void __user *) sp;
L
Linus Torvalds 已提交
403 404
}

405
int ia32_setup_frame(int sig, struct k_sigaction *ka,
406
		     compat_sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
407
{
408
	struct sigframe_ia32 __user *frame;
409
	void __user *restorer;
L
Linus Torvalds 已提交
410
	int err = 0;
411
	void __user *fpstate = NULL;
L
Linus Torvalds 已提交
412

413 414 415 416 417 418 419 420 421 422 423
	/* copy_to_user optimizes that into a single 8 byte store */
	static const struct {
		u16 poplmovl;
		u32 val;
		u16 int80;
	} __attribute__((packed)) code = {
		0xb858,		 /* popl %eax ; movl $...,%eax */
		__NR_ia32_sigreturn,
		0x80cd,		/* int $0x80 */
	};

424
	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
L
Linus Torvalds 已提交
425 426

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
427
		return -EFAULT;
L
Linus Torvalds 已提交
428

429
	if (__put_user(sig, &frame->sig))
430
		return -EFAULT;
L
Linus Torvalds 已提交
431

432
	if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
433
		return -EFAULT;
L
Linus Torvalds 已提交
434 435

	if (_COMPAT_NSIG_WORDS > 1) {
436 437
		if (__copy_to_user(frame->extramask, &set->sig[1],
				   sizeof(frame->extramask)))
438
			return -EFAULT;
L
Linus Torvalds 已提交
439 440
	}

441
	if (ka->sa.sa_flags & SA_RESTORER) {
442
		restorer = ka->sa.sa_restorer;
443 444
	} else {
		/* Return stub is in 32bit vsyscall page */
445
		if (current->mm->context.vdso)
446 447 448
			restorer = VDSO32_SYMBOL(current->mm->context.vdso,
						 sigreturn);
		else
449
			restorer = &frame->retcode;
450
	}
451

452 453 454 455 456 457 458 459 460 461
	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);

L
Linus Torvalds 已提交
462
	if (err)
463
		return -EFAULT;
L
Linus Torvalds 已提交
464 465

	/* Set up registers for signal handler */
466 467
	regs->sp = (unsigned long) frame;
	regs->ip = (unsigned long) ka->sa.sa_handler;
L
Linus Torvalds 已提交
468

469
	/* Make -mregparm=3 work */
470 471 472
	regs->ax = sig;
	regs->dx = 0;
	regs->cx = 0;
473

474 475
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
L
Linus Torvalds 已提交
476

477 478
	regs->cs = __USER32_CS;
	regs->ss = __USER32_DS;
L
Linus Torvalds 已提交
479

480
	return 0;
L
Linus Torvalds 已提交
481 482
}

483
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
484
			compat_sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
485
{
486
	struct rt_sigframe_ia32 __user *frame;
487
	void __user *restorer;
L
Linus Torvalds 已提交
488
	int err = 0;
489
	void __user *fpstate = NULL;
L
Linus Torvalds 已提交
490

491 492 493 494 495
	/* __copy_to_user optimizes that into a single 8 byte store */
	static const struct {
		u8 movl;
		u32 val;
		u16 int80;
496
		u8  pad;
497 498 499 500 501 502 503
	} __attribute__((packed)) code = {
		0xb8,
		__NR_ia32_rt_sigreturn,
		0x80cd,
		0,
	};

504
	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
L
Linus Torvalds 已提交
505 506

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
507
		return -EFAULT;
L
Linus Torvalds 已提交
508

509 510 511 512 513
	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);
L
Linus Torvalds 已提交
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
		/* 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);
		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);
L
Linus Torvalds 已提交
542 543

	if (err)
544
		return -EFAULT;
L
Linus Torvalds 已提交
545 546

	/* Set up registers for signal handler */
547 548
	regs->sp = (unsigned long) frame;
	regs->ip = (unsigned long) ka->sa.sa_handler;
L
Linus Torvalds 已提交
549

550
	/* Make -mregparm=3 work */
551 552 553
	regs->ax = sig;
	regs->dx = (unsigned long) &frame->info;
	regs->cx = (unsigned long) &frame->uc;
554

555 556
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
557 558 559

	regs->cs = __USER32_CS;
	regs->ss = __USER32_DS;
L
Linus Torvalds 已提交
560

561
	return 0;
L
Linus Torvalds 已提交
562
}
新手
引导
客服 返回
顶部