signal.c 14.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
/*
 *  arch/s390/kernel/signal.c
 *
4
 *    Copyright (C) IBM Corp. 1999,2006
Linus Torvalds's avatar
Linus Torvalds committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 *
 *    Based on Intel version
 * 
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
 */

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/personality.h>
#include <linux/binfmts.h>
Martin Schwidefsky's avatar
Martin Schwidefsky committed
27
#include <linux/tracehook.h>
28
#include <linux/syscalls.h>
29
#include <linux/compat.h>
Linus Torvalds's avatar
Linus Torvalds committed
30
31
32
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/lowcore.h>
33
#include "entry.h"
Linus Torvalds's avatar
Linus Torvalds committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))


typedef struct 
{
	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
	struct sigcontext sc;
	_sigregs sregs;
	int signo;
	__u8 retcode[S390_SYSCALL_SIZE];
} sigframe;

typedef struct 
{
	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
	__u8 retcode[S390_SYSCALL_SIZE];
	struct siginfo info;
	struct ucontext uc;
} rt_sigframe;

/*
 * Atomically swap in the new signal mask, and wait for a signal.
 */
58
SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
Linus Torvalds's avatar
Linus Torvalds committed
59
{
60
	sigset_t blocked;
Linus Torvalds's avatar
Linus Torvalds committed
61

62
63
64
65
	current->saved_sigmask = current->blocked;
	mask &= _BLOCKABLE;
	siginitset(&blocked, mask);
	set_current_blocked(&blocked);
66
	set_current_state(TASK_INTERRUPTIBLE);
67
68
69
	schedule();
	set_thread_flag(TIF_RESTORE_SIGMASK);
	return -ERESTARTNOHAND;
Linus Torvalds's avatar
Linus Torvalds committed
70
71
}

72
73
SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act,
		struct old_sigaction __user *, oact)
Linus Torvalds's avatar
Linus Torvalds committed
74
75
76
77
78
79
80
81
{
	struct k_sigaction new_ka, old_ka;
	int ret;

	if (act) {
		old_sigset_t mask;
		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
82
83
84
		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
		    __get_user(mask, &act->sa_mask))
Linus Torvalds's avatar
Linus Torvalds committed
85
86
87
88
89
90
91
92
93
			return -EFAULT;
		siginitset(&new_ka.sa.sa_mask, mask);
	}

	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

	if (!ret && oact) {
		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
94
95
96
		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
Linus Torvalds's avatar
Linus Torvalds committed
97
98
99
100
101
102
			return -EFAULT;
	}

	return ret;
}

103
104
SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss,
		stack_t __user *, uoss)
Linus Torvalds's avatar
Linus Torvalds committed
105
{
106
	struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds's avatar
Linus Torvalds committed
107
108
109
110
111
112
	return do_sigaltstack(uss, uoss, regs->gprs[15]);
}

/* Returns non-zero on fault. */
static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
{
113
114
	_sigregs user_sregs;

Linus Torvalds's avatar
Linus Torvalds committed
115
116
117
118
	save_access_regs(current->thread.acrs);

	/* Copy a 'clean' PSW mask to the user to avoid leaking
	   information about whether PER is currently on.  */
Gerald Schaefer's avatar
Gerald Schaefer committed
119
	user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
120
121
	user_sregs.regs.psw.addr = regs->psw.addr;
	memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
122
123
	memcpy(&user_sregs.regs.acrs, current->thread.acrs,
	       sizeof(sregs->regs.acrs));
Linus Torvalds's avatar
Linus Torvalds committed
124
125
126
127
128
	/* 
	 * We have to store the fp registers to current->thread.fp_regs
	 * to merge them with the emulated registers.
	 */
	save_fp_regs(&current->thread.fp_regs);
129
130
131
	memcpy(&user_sregs.fpregs, &current->thread.fp_regs,
	       sizeof(s390_fp_regs));
	return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs));
Linus Torvalds's avatar
Linus Torvalds committed
132
133
134
135
136
137
}

/* Returns positive number on error */
static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
{
	int err;
138
	_sigregs user_sregs;
Linus Torvalds's avatar
Linus Torvalds committed
139
140
141
142

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

143
	err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
Linus Torvalds's avatar
Linus Torvalds committed
144
145
	if (err)
		return err;
146
147
148
149
	regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
					user_sregs.regs.psw.mask);
	regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr;
	memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
150
151
	memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
	       sizeof(sregs->regs.acrs));
Linus Torvalds's avatar
Linus Torvalds committed
152
153
	restore_access_regs(current->thread.acrs);

154
155
	memcpy(&current->thread.fp_regs, &user_sregs.fpregs,
	       sizeof(s390_fp_regs));
Linus Torvalds's avatar
Linus Torvalds committed
156
157
158
	current->thread.fp_regs.fpc &= FPC_VALID_MASK;

	restore_fp_regs(&current->thread.fp_regs);
159
	regs->svcnr = 0;	/* disable syscall checks */
Linus Torvalds's avatar
Linus Torvalds committed
160
161
162
	return 0;
}

163
SYSCALL_DEFINE0(sigreturn)
Linus Torvalds's avatar
Linus Torvalds committed
164
{
165
	struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds's avatar
Linus Torvalds committed
166
167
168
169
170
171
172
173
	sigframe __user *frame = (sigframe __user *)regs->gprs[15];
	sigset_t set;

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
		goto badframe;
	sigdelsetmask(&set, ~_BLOCKABLE);
174
	set_current_blocked(&set);
Linus Torvalds's avatar
Linus Torvalds committed
175
176
177
178
179
180
181
182
	if (restore_sigregs(regs, &frame->sregs))
		goto badframe;
	return regs->gprs[2];
badframe:
	force_sig(SIGSEGV, current);
	return 0;
}

183
SYSCALL_DEFINE0(rt_sigreturn)
Linus Torvalds's avatar
Linus Torvalds committed
184
{
185
	struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds's avatar
Linus Torvalds committed
186
187
188
189
190
191
192
193
	rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
	sigset_t set;

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
	if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
		goto badframe;
	sigdelsetmask(&set, ~_BLOCKABLE);
194
	set_current_blocked(&set);
Linus Torvalds's avatar
Linus Torvalds committed
195
196
	if (restore_sigregs(regs, &frame->uc.uc_mcontext))
		goto badframe;
197
198
199
	if (do_sigaltstack(&frame->uc.uc_stack, NULL,
			   regs->gprs[15]) == -EFAULT)
		goto badframe;
Linus Torvalds's avatar
Linus Torvalds committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
	return regs->gprs[2];
badframe:
	force_sig(SIGSEGV, current);
	return 0;
}

/*
 * Set up a signal frame.
 */


/*
 * Determine which stack to use..
 */
static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
{
	unsigned long sp;

	/* Default to using normal stack */
	sp = regs->gprs[15];

222
223
224
225
	/* Overflow on alternate signal stack gives SIGSEGV. */
	if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
		return (void __user *) -1UL;

Linus Torvalds's avatar
Linus Torvalds committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
	/* This is the X/Open sanctioned signal stack switching.  */
	if (ka->sa.sa_flags & SA_ONSTACK) {
		if (! sas_ss_flags(sp))
			sp = current->sas_ss_sp + current->sas_ss_size;
	}

	/* This is the legacy signal stack switching. */
	else if (!user_mode(regs) &&
		 !(ka->sa.sa_flags & SA_RESTORER) &&
		 ka->sa.sa_restorer) {
		sp = (unsigned long) ka->sa.sa_restorer;
	}

	return (void __user *)((sp - frame_size) & -8ul);
}

static inline int map_signal(int sig)
{
	if (current_thread_info()->exec_domain
	    && current_thread_info()->exec_domain->signal_invmap
	    && sig < 32)
		return current_thread_info()->exec_domain->signal_invmap[sig];
	else
		return sig;
}

252
253
static int setup_frame(int sig, struct k_sigaction *ka,
		       sigset_t *set, struct pt_regs * regs)
Linus Torvalds's avatar
Linus Torvalds committed
254
255
256
257
258
259
260
{
	sigframe __user *frame;

	frame = get_sigframe(ka, regs, sizeof(sigframe));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
		goto give_sigsegv;

261
262
263
	if (frame == (void __user *) -1UL)
		goto give_sigsegv;

Linus Torvalds's avatar
Linus Torvalds committed
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
		goto give_sigsegv;

	if (save_sigregs(regs, &frame->sregs))
		goto give_sigsegv;
	if (__put_user(&frame->sregs, &frame->sc.sregs))
		goto give_sigsegv;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
	if (ka->sa.sa_flags & SA_RESTORER) {
                regs->gprs[14] = (unsigned long)
			ka->sa.sa_restorer | PSW_ADDR_AMODE;
	} else {
                regs->gprs[14] = (unsigned long)
			frame->retcode | PSW_ADDR_AMODE;
		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
	                       (u16 __user *)(frame->retcode)))
			goto give_sigsegv;
	}

	/* Set up backchain. */
	if (__put_user(regs->gprs[15], (addr_t __user *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (unsigned long) frame;
	regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (unsigned long) &frame->sc;

	/* We forgot to include these in the sigcontext.
	   To avoid breaking binary compatibility, they are passed as args. */
	regs->gprs[4] = current->thread.trap_no;
	regs->gprs[5] = current->thread.prot_addr;
300
	regs->gprs[6] = task_thread_info(current)->last_break;
Linus Torvalds's avatar
Linus Torvalds committed
301
302
303
304

	/* Place signal number on stack to allow backtrace from handler.  */
	if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
		goto give_sigsegv;
305
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
306
307
308

give_sigsegv:
	force_sigsegv(sig, current);
309
	return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
310
311
}

312
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Linus Torvalds's avatar
Linus Torvalds committed
313
314
315
316
317
318
319
320
321
			   sigset_t *set, struct pt_regs * regs)
{
	int err = 0;
	rt_sigframe __user *frame;

	frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
		goto give_sigsegv;

322
323
324
	if (frame == (void __user *) -1UL)
		goto give_sigsegv;

Linus Torvalds's avatar
Linus Torvalds committed
325
326
327
328
329
	if (copy_siginfo_to_user(&frame->info, info))
		goto give_sigsegv;

	/* Create the ucontext.  */
	err |= __put_user(0, &frame->uc.uc_flags);
Al Viro's avatar
Al Viro committed
330
331
	err |= __put_user(NULL, &frame->uc.uc_link);
	err |= __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
Linus Torvalds's avatar
Linus Torvalds committed
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
	err |= __put_user(sas_ss_flags(regs->gprs[15]),
			  &frame->uc.uc_stack.ss_flags);
	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
	err |= save_sigregs(regs, &frame->uc.uc_mcontext);
	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
	if (err)
		goto give_sigsegv;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
	if (ka->sa.sa_flags & SA_RESTORER) {
                regs->gprs[14] = (unsigned long)
			ka->sa.sa_restorer | PSW_ADDR_AMODE;
	} else {
                regs->gprs[14] = (unsigned long)
			frame->retcode | PSW_ADDR_AMODE;
348
349
350
		if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
			       (u16 __user *)(frame->retcode)))
			goto give_sigsegv;
Linus Torvalds's avatar
Linus Torvalds committed
351
352
353
354
355
356
357
358
359
360
361
362
363
	}

	/* Set up backchain. */
	if (__put_user(regs->gprs[15], (addr_t __user *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (unsigned long) frame;
	regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (unsigned long) &frame->info;
	regs->gprs[4] = (unsigned long) &frame->uc;
364
	regs->gprs[5] = task_thread_info(current)->last_break;
365
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
366
367
368

give_sigsegv:
	force_sigsegv(sig, current);
369
	return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
370
371
}

372
373
374
static int handle_signal(unsigned long sig, struct k_sigaction *ka,
			 siginfo_t *info, sigset_t *oldset,
			 struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
375
{
376
	sigset_t blocked;
377
378
	int ret;

Linus Torvalds's avatar
Linus Torvalds committed
379
380
	/* Set up the stack frame */
	if (ka->sa.sa_flags & SA_SIGINFO)
381
		ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds's avatar
Linus Torvalds committed
382
	else
383
		ret = setup_frame(sig, ka, oldset, regs);
384
385
386
387
388
389
390
	if (ret)
		return ret;
	sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
	if (!(ka->sa.sa_flags & SA_NODEFER))
		sigaddset(&blocked, sig);
	set_current_blocked(&blocked);
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
391
392
393
394
395
396
397
398
399
400
401
}

/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
402
void do_signal(struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
403
404
405
406
407
{
	unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
	siginfo_t info;
	int signr;
	struct k_sigaction ka;
408
	sigset_t *oldset;
Linus Torvalds's avatar
Linus Torvalds committed
409
410
411
412
413
414
415
416

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
417
		return;
Linus Torvalds's avatar
Linus Torvalds committed
418

419
420
421
	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
Linus Torvalds's avatar
Linus Torvalds committed
422
423
424
		oldset = &current->blocked;

	/* Are we from a system call? */
425
	if (regs->svcnr) {
Linus Torvalds's avatar
Linus Torvalds committed
426
427
428
429
430
431
		continue_addr = regs->psw.addr;
		restart_addr = continue_addr - regs->ilc;
		retval = regs->gprs[2];

		/* Prepare for system call restart.  We do this here so that a
		   debugger will see the already changed PSW. */
432
433
434
435
		switch (retval) {
		case -ERESTARTNOHAND:
		case -ERESTARTSYS:
		case -ERESTARTNOINTR:
Linus Torvalds's avatar
Linus Torvalds committed
436
437
			regs->gprs[2] = regs->orig_gpr2;
			regs->psw.addr = restart_addr;
438
439
			break;
		case -ERESTART_RESTARTBLOCK:
Linus Torvalds's avatar
Linus Torvalds committed
440
441
			regs->gprs[2] = -EINTR;
		}
442
		regs->svcnr = 0;	/* Don't deal with this again. */
Linus Torvalds's avatar
Linus Torvalds committed
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
	}

	/* Get signal to deliver.  When running under ptrace, at this point
	   the debugger may change all our registers ... */
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);

	/* Depending on the signal settings we may need to revert the
	   decision to restart the system call. */
	if (signr > 0 && regs->psw.addr == restart_addr) {
		if (retval == -ERESTARTNOHAND
		    || (retval == -ERESTARTSYS
			 && !(current->sighand->action[signr-1].sa.sa_flags
			      & SA_RESTART))) {
			regs->gprs[2] = -EINTR;
			regs->psw.addr = continue_addr;
		}
	}

	if (signr > 0) {
		/* Whee!  Actually deliver the signal.  */
Roland McGrath's avatar
Roland McGrath committed
463
		int ret;
464
#ifdef CONFIG_COMPAT
465
		if (is_compat_task()) {
Roland McGrath's avatar
Roland McGrath committed
466
			ret = handle_signal32(signr, &ka, &info, oldset, regs);
Linus Torvalds's avatar
Linus Torvalds committed
467
	        }
Roland McGrath's avatar
Roland McGrath committed
468
		else
Linus Torvalds's avatar
Linus Torvalds committed
469
#endif
Roland McGrath's avatar
Roland McGrath committed
470
471
			ret = handle_signal(signr, &ka, &info, oldset, regs);
		if (!ret) {
472
473
474
475
476
477
478
479
			/*
			 * A signal was successfully delivered; the saved
			 * sigmask will have been stored in the signal frame,
			 * and will be restored by sigreturn, so we can simply
			 * clear the TIF_RESTORE_SIGMASK flag.
			 */
			if (test_thread_flag(TIF_RESTORE_SIGMASK))
				clear_thread_flag(TIF_RESTORE_SIGMASK);
Roland McGrath's avatar
Roland McGrath committed
480

Martin Schwidefsky's avatar
Martin Schwidefsky committed
481
482
483
484
			/*
			 * Let tracing know that we've done the handler setup.
			 */
			tracehook_signal_handler(signr, &info, &ka, regs,
Martin Schwidefsky's avatar
Martin Schwidefsky committed
485
					test_thread_flag(TIF_SINGLE_STEP));
486
487
488
489
490
491
492
493
494
495
		}
		return;
	}

	/*
	 * If there's no signal to deliver, we just put the saved sigmask back.
	 */
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
496
497
498
499
500
501
502
503
504
	}

	/* Restart a different system call. */
	if (retval == -ERESTART_RESTARTBLOCK
	    && regs->psw.addr == continue_addr) {
		regs->gprs[2] = __NR_restart_syscall;
		set_thread_flag(TIF_RESTART_SVC);
	}
}
Martin Schwidefsky's avatar
Martin Schwidefsky committed
505
506
507
508
509

void do_notify_resume(struct pt_regs *regs)
{
	clear_thread_flag(TIF_NOTIFY_RESUME);
	tracehook_notify_resume(regs);
510
511
	if (current->replacement_session_keyring)
		key_replace_session_keyring();
Martin Schwidefsky's avatar
Martin Schwidefsky committed
512
}