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

Commit 392c2180 authored by David S. Miller's avatar David S. Miller
Browse files

sparc: Don't mask signal when we can't setup signal frame.



Don't invoke the signal handler tracehook in that situation
either.

Reported-by: default avatarAl Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 05c5e769
Loading
Loading
Loading
Loading
+34 −21
Original line number Diff line number Diff line
@@ -511,7 +511,7 @@ static void flush_signal_insns(unsigned long address)

}

static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
			 int signo, sigset_t *oldset)
{
	struct signal_frame32 __user *sf;
@@ -620,11 +620,14 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,

sigill:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signo, current);
	return -EFAULT;
}

static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
			    unsigned long signr, sigset_t *oldset,
			    siginfo_t *info)
{
@@ -738,22 +741,30 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,

		flush_signal_insns(address);
	}
	return;
	return 0;

sigill:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signr, current);
	return -EFAULT;
}

static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
				  siginfo_t *info,
				  sigset_t *oldset, struct pt_regs *regs)
{
	int err;

	if (ka->sa.sa_flags & SA_SIGINFO)
		setup_rt_frame32(ka, regs, signr, oldset, info);
		err = setup_rt_frame32(ka, regs, signr, oldset, info);
	else
		setup_frame32(ka, regs, signr, oldset);
		err = setup_frame32(ka, regs, signr, oldset);

	if (err)
		return err;

	spin_lock_irq(&current->sighand->siglock);
	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -761,6 +772,10 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
		sigaddset(&current->blocked,signr);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	tracehook_signal_handler(signr, info, ka, regs, 0);

	return 0;
}

static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
@@ -807,16 +822,14 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs,
	if (signr > 0) {
		if (restart_syscall)
			syscall_restart32(orig_i0, regs, &ka.sa);
		handle_signal32(signr, &ka, &info, oldset, regs);

		if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) {
			/* 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 TS_RESTORE_SIGMASK flag.
			 */
			current_thread_info()->status &= ~TS_RESTORE_SIGMASK;

		tracehook_signal_handler(signr, &info, &ka, regs, 0);
		}
		return;
	}
	if (restart_syscall &&
+33 −20
Original line number Diff line number Diff line
@@ -315,7 +315,7 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
	return err;
}

static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
		       int signo, sigset_t *oldset)
{
	struct signal_frame __user *sf;
@@ -384,15 +384,18 @@ static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
		/* Flush instruction space. */
		flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
	}
	return;
	return 0;

sigill_and_return:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signo, current);
	return -EFAULT;
}

static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
			  int signo, sigset_t *oldset, siginfo_t *info)
{
	struct rt_signal_frame __user *sf;
@@ -466,22 +469,30 @@ static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
		/* Flush instruction space. */
		flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
	}
	return;
	return 0;

sigill:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signo, current);
	return -EFAULT;
}

static inline void
static inline int
handle_signal(unsigned long signr, struct k_sigaction *ka,
	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
	int err;

	if (ka->sa.sa_flags & SA_SIGINFO)
		setup_rt_frame(ka, regs, signr, oldset, info);
		err = setup_rt_frame(ka, regs, signr, oldset, info);
	else
		setup_frame(ka, regs, signr, oldset);
		err = setup_frame(ka, regs, signr, oldset);

	if (err)
		return err;

	spin_lock_irq(&current->sighand->siglock);
	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -489,6 +500,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
		sigaddset(&current->blocked, signr);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	tracehook_signal_handler(signr, info, ka, regs, 0);

	return 0;
}

static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -546,8 +561,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
	if (signr > 0) {
		if (restart_syscall)
			syscall_restart(orig_i0, regs, &ka.sa);
		handle_signal(signr, &ka, &info, oldset, regs);

		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
			/* 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
@@ -555,8 +569,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
			 */
			if (test_thread_flag(TIF_RESTORE_SIGMASK))
				clear_thread_flag(TIF_RESTORE_SIGMASK);

		tracehook_signal_handler(signr, &info, &ka, regs, 0);
		}
		return;
	}
	if (restart_syscall &&
+26 −17
Original line number Diff line number Diff line
@@ -409,7 +409,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *
	return (void __user *) sp;
}

static inline void
static inline int
setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
	       int signo, sigset_t *oldset, siginfo_t *info)
{
@@ -483,26 +483,37 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
	}
	/* 4. return to kernel instructions */
	regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
	return;
	return 0;

sigill:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signo, current);
	return -EFAULT;
}

static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,
				siginfo_t *info,
				sigset_t *oldset, struct pt_regs *regs)
{
	setup_rt_frame(ka, regs, signr, oldset,
	int err;

	err = setup_rt_frame(ka, regs, signr, oldset,
			     (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
	if (err)
		return err;
	spin_lock_irq(&current->sighand->siglock);
	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
	if (!(ka->sa.sa_flags & SA_NOMASK))
		sigaddset(&current->blocked,signr);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	tracehook_signal_handler(signr, info, ka, regs, 0);

	return 0;
}

static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -571,16 +582,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
	if (signr > 0) {
		if (restart_syscall)
			syscall_restart(orig_i0, regs, &ka.sa);
		handle_signal(signr, &ka, &info, oldset, regs);

		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
			/* 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 TS_RESTORE_SIGMASK flag.
			 */
			current_thread_info()->status &= ~TS_RESTORE_SIGMASK;

		tracehook_signal_handler(signr, &info, &ka, regs, 0);
		}
		return;
	}
	if (restart_syscall &&