ia32_signal.c 14.0 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
	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;
70 71 72 73
			case __SI_SYS >> 16:
				put_user_ex(from->si_syscall, &to->si_syscall);
				put_user_ex(from->si_arch, &to->si_arch);
				break;
74
			case __SI_CHLD >> 16:
75 76 77 78 79 80 81
				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);
				}
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
				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 已提交
103
		}
104 105
	} put_user_catch(err);

L
Linus Torvalds 已提交
106 107 108 109 110
	return err;
}

int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
111
	int err = 0;
L
Linus Torvalds 已提交
112
	u32 ptr32;
113 114

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

117 118 119 120
	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 已提交
121

122 123 124 125 126
		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 已提交
127 128 129 130

	return err;
}

131
asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
L
Linus Torvalds 已提交
132
{
133 134
	sigset_t blocked;
	siginitset(&blocked, mask);
A
Al Viro 已提交
135
	return sigsuspend(&blocked);
L
Linus Torvalds 已提交
136 137
}

138 139 140
asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
				  stack_ia32_t __user *uoss_ptr,
				  struct pt_regs *regs)
L
Linus Torvalds 已提交
141
{
142
	stack_t uss, uoss;
143
	int ret, err = 0;
144 145 146
	mm_segment_t seg;

	if (uss_ptr) {
L
Linus Torvalds 已提交
147
		u32 ptr;
148 149

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

/*
 * Do a signal return; undo the signal stack.
 */
186 187 188 189 190 191 192 193
#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)

194
#define COPY(x)			{		\
195
	get_user_ex(regs->x, &sc->x);		\
L
Linus Torvalds 已提交
196 197
}

198 199 200 201 202 203 204 205 206
#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 已提交
207

208
#define RELOAD_SEG(seg)		{		\
209 210
	unsigned int pre = GET_SEG(seg);	\
	unsigned int cur = get_user_seg(seg);	\
211 212
	pre |= 3;				\
	if (pre != cur)				\
213
		set_user_seg(seg, pre);		\
214
}
215 216 217

static int ia32_restore_sigcontext(struct pt_regs *regs,
				   struct sigcontext_ia32 __user *sc,
218
				   unsigned int *pax)
219
{
220
	unsigned int tmpflags, err = 0;
221
	void __user *buf;
222 223 224 225 226
	u32 tmp;

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

227 228 229 230 231 232 233
	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.
		 */
234
		RELOAD_SEG(gs);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
		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 已提交
258 259 260 261 262
	return err;
}

asmlinkage long sys32_sigreturn(struct pt_regs *regs)
{
263
	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
L
Linus Torvalds 已提交
264
	sigset_t set;
265
	unsigned int ax;
L
Linus Torvalds 已提交
266 267 268 269 270

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__get_user(set.sig[0], &frame->sc.oldmask)
	    || (_COMPAT_NSIG_WORDS > 1
271 272
		&& __copy_from_user((((char *) &set.sig) + 4),
				    &frame->extramask,
L
Linus Torvalds 已提交
273 274 275
				    sizeof(frame->extramask))))
		goto badframe;

276
	set_current_blocked(&set);
277

278
	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
L
Linus Torvalds 已提交
279
		goto badframe;
280
	return ax;
L
Linus Torvalds 已提交
281 282 283 284

badframe:
	signal_fault(regs, frame, "32bit sigreturn");
	return 0;
285
}
L
Linus Torvalds 已提交
286 287 288

asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
{
289
	struct rt_sigframe_ia32 __user *frame;
L
Linus Torvalds 已提交
290
	sigset_t set;
291
	unsigned int ax;
L
Linus Torvalds 已提交
292 293
	struct pt_regs tregs;

294
	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
L
Linus Torvalds 已提交
295 296 297 298 299 300

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

301
	set_current_blocked(&set);
302

303
	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
L
Linus Torvalds 已提交
304 305 306 307 308 309
		goto badframe;

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

310
	return ax;
L
Linus Torvalds 已提交
311 312

badframe:
313
	signal_fault(regs, frame, "32bit rt sigreturn");
L
Linus Torvalds 已提交
314
	return 0;
315
}
L
Linus Torvalds 已提交
316 317 318 319 320

/*
 * Set up a signal frame.
 */

321
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
322
				 void __user *fpstate,
323
				 struct pt_regs *regs, unsigned int mask)
L
Linus Torvalds 已提交
324
{
325
	int err = 0;
L
Linus Torvalds 已提交
326

327
	put_user_try {
328 329 330 331
		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);
332 333 334 335 336 337 338 339 340

		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);
341
		put_user_ex(current->thread.trap_nr, &sc->trapno);
342 343 344 345 346 347 348 349 350 351 352 353 354
		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 已提交
355 356 357 358 359 360 361

	return err;
}

/*
 * Determine which stack to use..
 */
362
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
363
				 size_t frame_size,
364
				 void **fpstate)
L
Linus Torvalds 已提交
365
{
366
	unsigned long sp;
L
Linus Torvalds 已提交
367 368

	/* Default to using normal stack */
369
	sp = regs->sp;
L
Linus Torvalds 已提交
370 371 372

	/* This is the X/Open sanctioned signal stack switching.  */
	if (ka->sa.sa_flags & SA_ONSTACK) {
373 374
		if (sas_ss_flags(sp) == 0)
			sp = current->sas_ss_sp + current->sas_ss_size;
L
Linus Torvalds 已提交
375 376 377
	}

	/* This is the legacy signal stack switching. */
378
	else if ((regs->ss & 0xffff) != __USER32_DS &&
L
Linus Torvalds 已提交
379
		!(ka->sa.sa_flags & SA_RESTORER) &&
380
		 ka->sa.sa_restorer)
381
		sp = (unsigned long) ka->sa.sa_restorer;
L
Linus Torvalds 已提交
382

383 384 385
	if (used_math()) {
		sp = sp - sig_xstate_ia32_size;
		*fpstate = (struct _fpstate_ia32 *) sp;
386 387
		if (save_i387_xstate_ia32(*fpstate) < 0)
			return (void __user *) -1L;
388 389
	}

390
	sp -= frame_size;
391 392
	/* Align the stack pointer according to the i386 ABI,
	 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
393 394
	sp = ((sp + 4) & -16ul) - 4;
	return (void __user *) sp;
L
Linus Torvalds 已提交
395 396
}

397
int ia32_setup_frame(int sig, struct k_sigaction *ka,
398
		     compat_sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
399
{
400
	struct sigframe_ia32 __user *frame;
401
	void __user *restorer;
L
Linus Torvalds 已提交
402
	int err = 0;
403
	void __user *fpstate = NULL;
L
Linus Torvalds 已提交
404

405 406 407 408 409 410 411 412 413 414 415
	/* 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 */
	};

416
	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
L
Linus Torvalds 已提交
417 418

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

421
	if (__put_user(sig, &frame->sig))
422
		return -EFAULT;
L
Linus Torvalds 已提交
423

424
	if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
425
		return -EFAULT;
L
Linus Torvalds 已提交
426 427

	if (_COMPAT_NSIG_WORDS > 1) {
428 429
		if (__copy_to_user(frame->extramask, &set->sig[1],
				   sizeof(frame->extramask)))
430
			return -EFAULT;
L
Linus Torvalds 已提交
431 432
	}

433
	if (ka->sa.sa_flags & SA_RESTORER) {
434
		restorer = ka->sa.sa_restorer;
435 436
	} else {
		/* Return stub is in 32bit vsyscall page */
437
		if (current->mm->context.vdso)
438 439 440
			restorer = VDSO32_SYMBOL(current->mm->context.vdso,
						 sigreturn);
		else
441
			restorer = &frame->retcode;
442
	}
443

444 445 446 447 448 449 450 451 452 453
	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 已提交
454
	if (err)
455
		return -EFAULT;
L
Linus Torvalds 已提交
456 457

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

461
	/* Make -mregparm=3 work */
462 463 464
	regs->ax = sig;
	regs->dx = 0;
	regs->cx = 0;
465

466 467
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
L
Linus Torvalds 已提交
468

469 470
	regs->cs = __USER32_CS;
	regs->ss = __USER32_DS;
L
Linus Torvalds 已提交
471

472
	return 0;
L
Linus Torvalds 已提交
473 474
}

475
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
476
			compat_sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
477
{
478
	struct rt_sigframe_ia32 __user *frame;
479
	void __user *restorer;
L
Linus Torvalds 已提交
480
	int err = 0;
481
	void __user *fpstate = NULL;
L
Linus Torvalds 已提交
482

483 484 485 486 487
	/* __copy_to_user optimizes that into a single 8 byte store */
	static const struct {
		u8 movl;
		u32 val;
		u16 int80;
488
		u8  pad;
489 490 491 492 493 494 495
	} __attribute__((packed)) code = {
		0xb8,
		__NR_ia32_rt_sigreturn,
		0x80cd,
		0,
	};

496
	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
L
Linus Torvalds 已提交
497 498

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

501 502 503 504 505
	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 已提交
506

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
		/* 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 已提交
534 535

	if (err)
536
		return -EFAULT;
L
Linus Torvalds 已提交
537 538

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

542
	/* Make -mregparm=3 work */
543 544 545
	regs->ax = sig;
	regs->dx = (unsigned long) &frame->info;
	regs->cx = (unsigned long) &frame->uc;
546

547 548
	loadsegment(ds, __USER32_DS);
	loadsegment(es, __USER32_DS);
549 550 551

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

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