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

Commit 64a76d0d authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

signal: Fix sending signals with siginfo



Today sending a signal with rt_sigqueueinfo and receving it on
a signalfd does not work reliably.  The issue is that reading
a signalfd instead of returning a siginfo returns a signalfd_siginfo and
the kernel must convert from one to the other.

The kernel does not currently have the code to deduce which union
members of struct siginfo are in use.

In this patchset I fix that by introducing a new function siginfo_layout
that can look at a siginfo and report which union member of struct
siginfo is in use.  Before that I clean up how we populate struct
siginfo.

The siginfo structure has two key members si_signo and si_code.  Some
si_codes are signal specific and for those it takes si_signo and si_code
to indicate the members of siginfo that are valid.  The rest of the
si_code values are signal independent like SI_USER, SI_KERNEL, SI_QUEUE,
and SI_TIMER and only si_code is needed to indicate which members of
siginfo are valid.

At least that is how POSIX documents them, and how common sense would
indicate they should function.  In practice we have been rather sloppy
about maintaining the ABI in linux and we have some exceptions.  We have
a couple of buggy architectures that make SI_USER mean something
different when combined with SIGFPE or SIGTRAP.  Worse we have
fcntl(F_SETSIG) which results in the si_codes POLL_IN, POLL_OUT,
POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP being sent with any arbitrary
signal, while the values are in a range that overlaps the signal
specific si_codes.

Thankfully the ambiguous cases with the POLL_NNN si_codes are for
things no sane persion would do that so we can rectify the situtation.
AKA no one cares so we won't cause a regression fixing it.

As part of fixing this I stop leaking the __SI_xxxx codes to userspace
and stop storing them in the high 16bits of si_code.  Making the kernel
code fundamentally simpler.  We have already confirmed that the one
application that would see this difference in kernel behavior CRIU won't
be affected by this change as it copies values verbatim from one kernel
interface to another.

v3:
   - Corrected the patches so they bisect properly
v2:
   - Benchmarked the code to confirm no performance changes are visible.
   - Reworked the first couple of patches so that TRAP_FIXME and
     FPE_FIXME are not exported to userspace.
   - Rebased on top of the siginfo cleanup that came in v4.13-rc1
   - Updated alpha to use both TRAP_FIXME and FPE_FIXME

Eric W. Biederman (7):
      signal/alpha: Document a conflict with SI_USER for SIGTRAP
      signal/ia64: Document a conflict with SI_USER with SIGFPE
      signal/sparc: Document a conflict with SI_USER with SIGFPE
      signal/mips: Document a conflict with SI_USER with SIGFPE
      signal/testing: Don't look for __SI_FAULT in userspace
      fcntl: Don't use ambiguous SIG_POLL si_codes
      signal: Remove kernel interal si_code magic

Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parents 4d28df61 cc731525
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -6,4 +6,18 @@

#include <asm-generic/siginfo.h>

/*
 * SIGFPE si_codes
 */
#ifdef __KERNEL__
#define FPE_FIXME	0	/* Broken dup of SI_USER */
#endif /* __KERNEL__ */

/*
 * SIGTRAP si_codes
 */
#ifdef __KERNEL__
#define TRAP_FIXME	0	/* Broken dup of SI_USER */
#endif /* __KERNEL__ */

#endif
+3 −3
Original line number Diff line number Diff line
@@ -278,7 +278,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
	      case 1: /* bugcheck */
		info.si_signo = SIGTRAP;
		info.si_errno = 0;
		info.si_code = __SI_FAULT;
		info.si_code = TRAP_FIXME;
		info.si_addr = (void __user *) regs->pc;
		info.si_trapno = 0;
		send_sig_info(SIGTRAP, &info, current);
@@ -318,7 +318,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
			break;
		case GEN_ROPRAND:
			signo = SIGFPE;
			code = __SI_FAULT;
			code = FPE_FIXME;
			break;

		case GEN_DECOVF:
@@ -340,7 +340,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
		case GEN_SUBRNG7:
		default:
			signo = SIGTRAP;
			code = __SI_FAULT;
			code = TRAP_FIXME;
			break;
		}

+9 −14
Original line number Diff line number Diff line
@@ -142,25 +142,25 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
	 */
	err = __put_user(from->si_signo, &to->si_signo);
	err |= __put_user(from->si_errno, &to->si_errno);
	err |= __put_user((short)from->si_code, &to->si_code);
	err |= __put_user(from->si_code, &to->si_code);
	if (from->si_code < 0)
		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
				      SI_PAD_SIZE);
	else switch (from->si_code & __SI_MASK) {
	case __SI_KILL:
	else switch (siginfo_layout(from->si_signo, from->si_code)) {
	case SIL_KILL:
		err |= __put_user(from->si_pid, &to->si_pid);
		err |= __put_user(from->si_uid, &to->si_uid);
		break;
	case __SI_TIMER:
	case SIL_TIMER:
		 err |= __put_user(from->si_tid, &to->si_tid);
		 err |= __put_user(from->si_overrun, &to->si_overrun);
		 err |= __put_user(from->si_int, &to->si_int);
		break;
	case __SI_POLL:
	case SIL_POLL:
		err |= __put_user(from->si_band, &to->si_band);
		err |= __put_user(from->si_fd, &to->si_fd);
		break;
	case __SI_FAULT:
	case SIL_FAULT:
		err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
				  &to->si_addr);
#ifdef BUS_MCEERR_AO
@@ -173,29 +173,24 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
			err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
#endif
		break;
	case __SI_CHLD:
	case SIL_CHLD:
		err |= __put_user(from->si_pid, &to->si_pid);
		err |= __put_user(from->si_uid, &to->si_uid);
		err |= __put_user(from->si_status, &to->si_status);
		err |= __put_user(from->si_utime, &to->si_utime);
		err |= __put_user(from->si_stime, &to->si_stime);
		break;
	case __SI_RT: /* This is not generated by the kernel as of now. */
	case __SI_MESGQ: /* But this is */
	case SIL_RT:
		err |= __put_user(from->si_pid, &to->si_pid);
		err |= __put_user(from->si_uid, &to->si_uid);
		err |= __put_user(from->si_int, &to->si_int);
		break;
	case __SI_SYS:
	case SIL_SYS:
		err |= __put_user((compat_uptr_t)(unsigned long)
				from->si_call_addr, &to->si_call_addr);
		err |= __put_user(from->si_syscall, &to->si_syscall);
		err |= __put_user(from->si_arch, &to->si_arch);
		break;
	default: /* this is just in case for now ... */
		err |= __put_user(from->si_pid, &to->si_pid);
		err |= __put_user(from->si_uid, &to->si_uid);
		break;
	}
	return err;
}
+19 −11
Original line number Diff line number Diff line
@@ -14,28 +14,36 @@

#define si_uid16	_sifields._kill._uid

#define ILL_ILLPARAOP	(__SI_FAULT|2)	/* illegal opcode combine ********** */
#define ILL_ILLEXCPT	(__SI_FAULT|4)	/* unrecoverable exception ********** */
#define ILL_CPLB_VI	(__SI_FAULT|9)	/* D/I CPLB protect violation ******** */
#define ILL_CPLB_MISS	(__SI_FAULT|10)	/* D/I CPLB miss ******** */
#define ILL_CPLB_MULHIT	(__SI_FAULT|11)	/* D/I CPLB multiple hit ******** */
#define ILL_ILLPARAOP	2	/* illegal opcode combine ********** */
#define ILL_ILLEXCPT	4	/* unrecoverable exception ********** */
#define ILL_CPLB_VI	9	/* D/I CPLB protect violation ******** */
#define ILL_CPLB_MISS	10	/* D/I CPLB miss ******** */
#define ILL_CPLB_MULHIT	11	/* D/I CPLB multiple hit ******** */
#undef NSIGILL
#define NSIGILL         11

/*
 * SIGBUS si_codes
 */
#define BUS_OPFETCH	(__SI_FAULT|4)	/* error from instruction fetch ******** */
#define BUS_OPFETCH	4	/* error from instruction fetch ******** */
#undef NSIGBUS
#define NSIGBUS		4

/*
 * SIGTRAP si_codes
 */
#define TRAP_STEP	(__SI_FAULT|1)	/* single-step breakpoint************* */
#define TRAP_TRACEFLOW	(__SI_FAULT|2)	/* trace buffer overflow ************* */
#define TRAP_WATCHPT	(__SI_FAULT|3)	/* watchpoint match      ************* */
#define TRAP_ILLTRAP	(__SI_FAULT|4)	/* illegal trap          ************* */
#define TRAP_STEP	1	/* single-step breakpoint************* */
#define TRAP_TRACEFLOW	2	/* trace buffer overflow ************* */
#define TRAP_WATCHPT	3	/* watchpoint match      ************* */
#define TRAP_ILLTRAP	4	/* illegal trap          ************* */
#undef NSIGTRAP
#define NSIGTRAP	4

/*
 * SIGSEGV si_codes
 */
#define SEGV_STACKFLOW	(__SI_FAULT|3)	/* stack overflow */
#define SEGV_STACKFLOW	3	/* stack overflow */
#undef NSIGSEGV
#define NSIGSEGV	3

#endif /* _UAPI_BFIN_SIGINFO_H */
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
#include <linux/types.h>
#include <asm-generic/siginfo.h>

#define FPE_MDAOVF	(__SI_FAULT|9)	/* media overflow */
#define FPE_MDAOVF	9	/* media overflow */
#undef NSIGFPE
#define NSIGFPE		9

Loading