Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0caca697 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k:
  m68knommu: Need to check __get_user()/__put_user() result
  m68knommu: signal.c __user annotations
  m68knommu: Equivalent of "m68k: handle new gcc's"
  m68knommu: f_pcr has been gone since headers' merge
  m68knommu: Don't lose state if sigframe setup fails
  m68knommu: Handle multiple pending signals
  m68knommu: Switch to saner sigsuspend
  m68knommu: Don't bother with SA_ONESHOT
  m68k: Check __get_user()/__put_user() return value
  m68k: Missing syscall_trace() on sigreturn
  m68k: Fix stack mangling logics in sigreturn
  m68k: If we fail to set sigframe up, just leave regs alone...
  m68k: Don't lose state if sigframe setup fails
  m68k: Simplify the singlestepping handling in signals
  m68k: Switch to saner sigsuspend()
  m68k: Resetting sa_handler in local copy of k_sigaction is pointless
  m68k/sun3: Kill pte_unmap() warnings
parents ecacc6c7 751c88a2
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -217,9 +217,8 @@ static inline pte_t pgoff_to_pte(unsigned off)
/* Find an entry in the third-level pagetable. */
#define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
#define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address))
/* FIXME: should we bother with kmap() here? */
#define pte_offset_map(pmd, address) ((pte_t *)kmap(pmd_page(*pmd)) + pte_index(address))
#define pte_unmap(pte) kunmap(pte)
#define pte_offset_map(pmd, address) ((pte_t *)page_address(pmd_page(*pmd)) + pte_index(address))
#define pte_unmap(pte) do { } while (0)

/* Macros to (de)construct the fake PTEs representing swap pages. */
#define __swp_type(x)		((x).val & 0x7F)
+1 −0
Original line number Diff line number Diff line
@@ -104,5 +104,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_TRACE	15	/* syscall trace active */
#define TIF_MEMDIE		16	/* is terminating due to OOM killer */
#define TIF_FREEZE		17	/* thread is freezing for suspend */
#define TIF_RESTORE_SIGMASK	18	/* restore signal mask in do_signal */

#endif	/* _ASM_M68K_THREAD_INFO_H */
+1 −0
Original line number Diff line number Diff line
@@ -373,6 +373,7 @@
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND

/*
 * "Conditional" syscalls
+6 −24
Original line number Diff line number Diff line
@@ -99,7 +99,10 @@ do_trace_exit:
	jra	.Lret_from_exception

ENTRY(ret_from_signal)
	RESTORE_SWITCH_STACK
	tstb	%curptr@(TASK_INFO+TINFO_FLAGS+2)
	jge	1f
	jbsr	syscall_trace
1:	RESTORE_SWITCH_STACK
	addql	#4,%sp
/* on 68040 complete pending writebacks if any */
#ifdef CONFIG_M68040
@@ -174,16 +177,11 @@ do_signal_return:
	subql	#4,%sp			| dummy return address
	SAVE_SWITCH_STACK
	pea	%sp@(SWITCH_STACK_SIZE)
	clrl	%sp@-
	bsrl	do_signal
	addql	#8,%sp
	addql	#4,%sp
	RESTORE_SWITCH_STACK
	addql	#4,%sp
	tstl	%d0
	jeq	resume_userspace
	| when single stepping into handler stop at the first insn
	btst	#6,%curptr@(TASK_INFO+TINFO_FLAGS+2)
	jeq	resume_userspace
	jbra	resume_userspace

do_delayed_trace:
	bclr	#7,%sp@(PT_OFF_SR)	| clear trace bit in SR
@@ -290,22 +288,6 @@ ENTRY(sys_vfork)
	RESTORE_SWITCH_STACK
	rts

ENTRY(sys_sigsuspend)
	SAVE_SWITCH_STACK
	pea	%sp@(SWITCH_STACK_SIZE)
	jbsr	do_sigsuspend
	addql	#4,%sp
	RESTORE_SWITCH_STACK
	rts

ENTRY(sys_rt_sigsuspend)
	SAVE_SWITCH_STACK
	pea	%sp@(SWITCH_STACK_SIZE)
	jbsr	do_rt_sigsuspend
	addql	#4,%sp
	RESTORE_SWITCH_STACK
	rts

ENTRY(sys_sigreturn)
	SAVE_SWITCH_STACK
	jbsr	do_sigreturn
+131 −183
Original line number Diff line number Diff line
@@ -51,8 +51,6 @@

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

asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);

const int frame_extra_sizes[16] = {
  [1]	= -1, /* sizeof(((struct frame *)0)->un.fmt1), */
  [2]	= sizeof(((struct frame *)0)->un.fmt2),
@@ -74,51 +72,21 @@ const int frame_extra_sizes[16] = {
/*
 * Atomically swap in the new signal mask, and wait for a signal.
 */
asmlinkage int do_sigsuspend(struct pt_regs *regs)
asmlinkage int
sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
{
	old_sigset_t mask = regs->d3;
	sigset_t saveset;

	mask &= _BLOCKABLE;
	saveset = current->blocked;
	spin_lock_irq(&current->sighand->siglock);
	current->saved_sigmask = current->blocked;
	siginitset(&current->blocked, mask);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	regs->d0 = -EINTR;
	while (1) {
	current->state = TASK_INTERRUPTIBLE;
	schedule();
		if (do_signal(&saveset, regs))
			return -EINTR;
	}
}

asmlinkage int
do_rt_sigsuspend(struct pt_regs *regs)
{
	sigset_t __user *unewset = (sigset_t __user *)regs->d1;
	size_t sigsetsize = (size_t)regs->d2;
	sigset_t saveset, newset;

	/* XXX: Don't preclude handling different sized sigset_t's.  */
	if (sigsetsize != sizeof(sigset_t))
		return -EINVAL;
	set_restore_sigmask();

	if (copy_from_user(&newset, unewset, sizeof(newset)))
		return -EFAULT;
	sigdelsetmask(&newset, ~_BLOCKABLE);

	saveset = current->blocked;
	current->blocked = newset;
	recalc_sigpending();

	regs->d0 = -EINTR;
	while (1) {
		current->state = TASK_INTERRUPTIBLE;
		schedule();
		if (do_signal(&saveset, regs))
			return -EINTR;
	}
	return -ERESTARTNOHAND;
}

asmlinkage int
@@ -132,10 +100,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
		old_sigset_t mask;
		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
		    __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))
			return -EFAULT;
		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
		__get_user(mask, &act->sa_mask);
		siginitset(&new_ka.sa.sa_mask, mask);
	}

@@ -144,10 +112,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
	if (!ret && oact) {
		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
		    __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))
			return -EFAULT;
		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
	}

	return ret;
@@ -318,36 +286,10 @@ out:
	return err;
}

static inline int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp,
		   int *pd0)
static int mangle_kernel_stack(struct pt_regs *regs, int formatvec,
			       void __user *fp)
{
	int fsize, formatvec;
	struct sigcontext context;
	int err;

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

	/* get previous context */
	if (copy_from_user(&context, usc, sizeof(context)))
		goto badframe;

	/* restore passed registers */
	regs->d1 = context.sc_d1;
	regs->a0 = context.sc_a0;
	regs->a1 = context.sc_a1;
	regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
	regs->pc = context.sc_pc;
	regs->orig_d0 = -1;		/* disable syscall checks */
	wrusp(context.sc_usp);
	formatvec = context.sc_formatvec;
	regs->format = formatvec >> 12;
	regs->vector = formatvec & 0xfff;

	err = restore_fpu_state(&context);

	fsize = frame_extra_sizes[regs->format];
	int fsize = frame_extra_sizes[formatvec >> 12];
	if (fsize < 0) {
		/*
		 * user process trying to return with weird frame format
@@ -355,16 +297,22 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u
#ifdef DEBUG
		printk("user process returning with weird frame format\n");
#endif
		goto badframe;
		return 1;
	}
	if (!fsize) {
		regs->format = formatvec >> 12;
		regs->vector = formatvec & 0xfff;
	} else {
		struct switch_stack *sw = (struct switch_stack *)regs - 1;
		unsigned long buf[fsize / 2]; /* yes, twice as much */

	/* OK.	Make room on the supervisor stack for the extra junk,
	 * if necessary.
	 */
		/* that'll make sure that expansion won't crap over data */
		if (copy_from_user(buf + fsize / 4, fp, fsize))
			return 1;

	if (fsize) {
		struct switch_stack *sw = (struct switch_stack *)regs - 1;
		regs->d0 = context.sc_d0;
		/* point of no return */
		regs->format = formatvec >> 12;
		regs->vector = formatvec & 0xfff;
#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
		__asm__ __volatile__
			("   movel %0,%/a0\n\t"
@@ -376,30 +324,50 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u
			 "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
			 "   lsrl  #2,%1\n\t"
			 "   subql #1,%1\n\t"
			 "2: movesl %4@+,%2\n\t"
			 "3: movel %2,%/a0@+\n\t"
			 /* copy to the gap we'd made */
			 "2: movel %4@+,%/a0@+\n\t"
			 "   dbra %1,2b\n\t"
			 "   bral ret_from_signal\n"
			 "4:\n"
			 ".section __ex_table,\"a\"\n"
			 "   .align 4\n"
			 "   .long 2b,4b\n"
			 "   .long 3b,4b\n"
			 ".previous"
			 : /* no outputs, it doesn't ever return */
			 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
			   "n" (frame_offset), "a" (fp)
			   "n" (frame_offset), "a" (buf + fsize/4)
			 : "a0");
#undef frame_offset
		/*
		 * If we ever get here an exception occurred while
		 * building the above stack-frame.
		 */
		goto badframe;
	}
	return 0;
}

	*pd0 = context.sc_d0;
	return err;
static inline int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp)
{
	int formatvec;
	struct sigcontext context;
	int err;

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

	/* get previous context */
	if (copy_from_user(&context, usc, sizeof(context)))
		goto badframe;

	/* restore passed registers */
	regs->d0 = context.sc_d0;
	regs->d1 = context.sc_d1;
	regs->a0 = context.sc_a0;
	regs->a1 = context.sc_a1;
	regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
	regs->pc = context.sc_pc;
	regs->orig_d0 = -1;		/* disable syscall checks */
	wrusp(context.sc_usp);
	formatvec = context.sc_formatvec;

	err = restore_fpu_state(&context);

	if (err || mangle_kernel_stack(regs, formatvec, fp))
		goto badframe;

	return 0;

badframe:
	return 1;
@@ -407,9 +375,9 @@ badframe:

static inline int
rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
		    struct ucontext __user *uc, int *pd0)
		    struct ucontext __user *uc)
{
	int fsize, temp;
	int temp;
	greg_t __user *gregs = uc->uc_mcontext.gregs;
	unsigned long usp;
	int err;
@@ -443,65 +411,16 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
	regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
	regs->orig_d0 = -1;		/* disable syscall checks */
	err |= __get_user(temp, &uc->uc_formatvec);
	regs->format = temp >> 12;
	regs->vector = temp & 0xfff;

	err |= rt_restore_fpu_state(uc);

	if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
	if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
		goto badframe;

	fsize = frame_extra_sizes[regs->format];
	if (fsize < 0) {
		/*
		 * user process trying to return with weird frame format
		 */
#ifdef DEBUG
		printk("user process returning with weird frame format\n");
#endif
	if (mangle_kernel_stack(regs, temp, &uc->uc_extra))
		goto badframe;
	}

	/* OK.	Make room on the supervisor stack for the extra junk,
	 * if necessary.
	 */

	if (fsize) {
#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
		__asm__ __volatile__
			("   movel %0,%/a0\n\t"
			 "   subl %1,%/a0\n\t"     /* make room on stack */
			 "   movel %/a0,%/sp\n\t"  /* set stack pointer */
			 /* move switch_stack and pt_regs */
			 "1: movel %0@+,%/a0@+\n\t"
			 "   dbra %2,1b\n\t"
			 "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
			 "   lsrl  #2,%1\n\t"
			 "   subql #1,%1\n\t"
			 "2: movesl %4@+,%2\n\t"
			 "3: movel %2,%/a0@+\n\t"
			 "   dbra %1,2b\n\t"
			 "   bral ret_from_signal\n"
			 "4:\n"
			 ".section __ex_table,\"a\"\n"
			 "   .align 4\n"
			 "   .long 2b,4b\n"
			 "   .long 3b,4b\n"
			 ".previous"
			 : /* no outputs, it doesn't ever return */
			 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
			   "n" (frame_offset), "a" (&uc->uc_extra)
			 : "a0");
#undef frame_offset
		/*
		 * If we ever get here an exception occurred while
		 * building the above stack-frame.
		 */
		goto badframe;
	}

	*pd0 = regs->d0;
	return err;
	return 0;

badframe:
	return 1;
@@ -514,7 +433,6 @@ asmlinkage int do_sigreturn(unsigned long __unused)
	unsigned long usp = rdusp();
	struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
	sigset_t set;
	int d0;

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
@@ -528,9 +446,9 @@ asmlinkage int do_sigreturn(unsigned long __unused)
	current->blocked = set;
	recalc_sigpending();

	if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
	if (restore_sigcontext(regs, &frame->sc, frame + 1))
		goto badframe;
	return d0;
	return regs->d0;

badframe:
	force_sig(SIGSEGV, current);
@@ -544,7 +462,6 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
	unsigned long usp = rdusp();
	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
	sigset_t set;
	int d0;

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
@@ -555,9 +472,9 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
	current->blocked = set;
	recalc_sigpending();

	if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
	if (rt_restore_ucontext(regs, sw, &frame->uc))
		goto badframe;
	return d0;
	return regs->d0;

badframe:
	force_sig(SIGSEGV, current);
@@ -775,7 +692,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
	return (void __user *)((usp - frame_size) & -8UL);
}

static void setup_frame (int sig, struct k_sigaction *ka,
static int setup_frame (int sig, struct k_sigaction *ka,
			 sigset_t *set, struct pt_regs *regs)
{
	struct sigframe __user *frame;
@@ -793,10 +710,8 @@ static void setup_frame (int sig, struct k_sigaction *ka,

	frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);

	if (fsize) {
	if (fsize)
		err |= copy_to_user (frame + 1, regs + 1, fsize);
		regs->stkadj = fsize;
	}

	err |= __put_user((current_thread_info()->exec_domain
			   && current_thread_info()->exec_domain->signal_invmap
@@ -826,11 +741,21 @@ static void setup_frame (int sig, struct k_sigaction *ka,

	push_cache ((unsigned long) &frame->retcode);

	/* Set up registers for signal handler */
	/*
	 * Set up registers for signal handler.  All the state we are about
	 * to destroy is successfully copied to sigframe.
	 */
	wrusp ((unsigned long) frame);
	regs->pc = (unsigned long) ka->sa.sa_handler;

adjust_stack:
	/*
	 * This is subtle; if we build more than one sigframe, all but the
	 * first one will see frame format 0 and have fsize == 0, so we won't
	 * screw stkadj.
	 */
	if (fsize)
		regs->stkadj = fsize;

	/* Prepare to skip over the extra stuff in the exception frame.  */
	if (regs->stkadj) {
		struct pt_regs *tregs =
@@ -845,14 +770,14 @@ adjust_stack:
		tregs->pc = regs->pc;
		tregs->sr = regs->sr;
	}
	return;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	goto adjust_stack;
	return err;
}

static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
			    sigset_t *set, struct pt_regs *regs)
{
	struct rt_sigframe __user *frame;
@@ -869,10 +794,8 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,

	frame = get_sigframe(ka, regs, sizeof(*frame));

	if (fsize) {
	if (fsize)
		err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
		regs->stkadj = fsize;
	}

	err |= __put_user((current_thread_info()->exec_domain
			   && current_thread_info()->exec_domain->signal_invmap
@@ -914,11 +837,21 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,

	push_cache ((unsigned long) &frame->retcode);

	/* Set up registers for signal handler */
	/*
	 * Set up registers for signal handler.  All the state we are about
	 * to destroy is successfully copied to sigframe.
	 */
	wrusp ((unsigned long) frame);
	regs->pc = (unsigned long) ka->sa.sa_handler;

adjust_stack:
	/*
	 * This is subtle; if we build more than one sigframe, all but the
	 * first one will see frame format 0 and have fsize == 0, so we won't
	 * screw stkadj.
	 */
	if (fsize)
		regs->stkadj = fsize;

	/* Prepare to skip over the extra stuff in the exception frame.  */
	if (regs->stkadj) {
		struct pt_regs *tregs =
@@ -933,11 +866,11 @@ adjust_stack:
		tregs->pc = regs->pc;
		tregs->sr = regs->sr;
	}
	return;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	goto adjust_stack;
	return err;
}

static inline void
@@ -995,6 +928,7 @@ static void
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
	      sigset_t *oldset, struct pt_regs *regs)
{
	int err;
	/* are we from a system call? */
	if (regs->orig_d0 >= 0)
		/* If so, check system call restarting.. */
@@ -1002,17 +936,24 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,

	/* set up the stack frame */
	if (ka->sa.sa_flags & SA_SIGINFO)
		setup_rt_frame(sig, ka, info, oldset, regs);
		err = setup_rt_frame(sig, ka, info, oldset, regs);
	else
		setup_frame(sig, ka, oldset, regs);
		err = setup_frame(sig, ka, oldset, regs);

	if (ka->sa.sa_flags & SA_ONESHOT)
		ka->sa.sa_handler = SIG_DFL;
	if (err)
		return;

	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
	if (!(ka->sa.sa_flags & SA_NODEFER))
		sigaddset(&current->blocked,sig);
	recalc_sigpending();

	if (test_thread_flag(TIF_DELAYED_TRACE)) {
		regs->sr &= ~0x8000;
		send_sig(SIGTRAP, current, 1);
	}

	clear_thread_flag(TIF_RESTORE_SIGMASK);
}

/*
@@ -1020,22 +961,25 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 */
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
asmlinkage void do_signal(struct pt_regs *regs)
{
	siginfo_t info;
	struct k_sigaction ka;
	int signr;
	sigset_t *oldset;

	current->thread.esp0 = (unsigned long) regs;

	if (!oldset)
	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
		oldset = &current->blocked;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
		/* Whee!  Actually deliver the signal.  */
		handle_signal(signr, &ka, &info, oldset, regs);
		return 1;
		return;
	}

	/* Did we come from a system call? */
@@ -1043,5 +987,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
		/* Restart the system call - no handlers present */
		handle_restart(regs, NULL, 0);

	return 0;
	/* If there's no signal to deliver, we just restore the saved mask.  */
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
	}
}
Loading