Provide a freebsd32 implementation of sigqueue()

The previous misuse of sys_sigqueue() was sending random register or
stack garbage to 64-bit targets.  The freebsd32 implementation preserves
the sival_int member of value when signaling a 64-bit process.

Document the mixed ABI implementation of union sigval and the
incompability of sival_ptr with pointer integrity schemes.

Reviewed by:	kib, wblock
MFC after:	1 week
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D10605
This commit is contained in:
Brooks Davis 2017-05-05 18:49:39 +00:00
parent 7748ab43a3
commit f19351aad8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=317845
5 changed files with 64 additions and 12 deletions

View File

@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd March 10, 2012
.Dd May 5, 2017
.Dt SIGQUEUE 2
.Os
.Sh NAME
@ -129,7 +129,6 @@ does not exist.
.Xr kill 2 ,
.Xr sigaction 2 ,
.Xr sigpending 2 ,
.Xr sigqueue 2 ,
.Xr sigsuspend 2 ,
.Xr sigtimedwait 2 ,
.Xr sigwait 2 ,
@ -147,3 +146,18 @@ Support for
.Tn POSIX
realtime signal queue first appeared in
.Fx 7.0 .
.Sh CAVEATS
When using
.Nm
to send signals to a process which might have a different ABI
(for instance, one is 32-bit and the other 64-bit),
the
.Va sival_int
member of
.Fa value
can be delivered reliably, but the
.Va sival_ptr
may be truncated in endian dependent ways and must not be relied on.
Further, many pointer integrity schemes disallow sending pointers to other
processes, and this technique should not be used in programs intended to
be portable.

View File

@ -2477,6 +2477,32 @@ siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst)
dst->si_overrun = src->si_overrun;
}
#ifndef _FREEBSD32_SYSPROTO_H_
struct freebsd32_sigqueue_args {
pid_t pid;
int signum;
/* union sigval32 */ int value;
};
#endif
int
freebsd32_sigqueue(struct thread *td, struct freebsd32_sigqueue_args *uap)
{
union sigval sv;
/*
* On 32-bit ABIs, sival_int and sival_ptr are the same.
* On 64-bit little-endian ABIs, the low bits are the same.
* In 64-bit big-endian ABIs, sival_int overlaps with
* sival_ptr's HIGH bits. We choose to support sival_int
* rather than sival_ptr in this case as it seems to be
* more common.
*/
bzero(&sv, sizeof(sv));
sv.sival_int = uap->value;
return (kern_sigqueue(td, uap->pid, uap->signum, &sv));
}
int
freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *uap)
{

View File

@ -819,8 +819,8 @@
455 AUE_THR_NEW STD { int freebsd32_thr_new( \
struct thr_param32 *param, \
int param_size); }
456 AUE_NULL NOPROTO { int sigqueue(pid_t pid, int signum, \
void *value); }
456 AUE_NULL STD { int freebsd32_sigqueue(pid_t pid, \
int signum, int value); }
457 AUE_MQ_OPEN NOSTD { int freebsd32_kmq_open( \
const char *path, int flags, mode_t mode, \
const struct mq_attr32 *attr); }

View File

@ -1843,34 +1843,44 @@ struct sigqueue_args {
#endif
int
sys_sigqueue(struct thread *td, struct sigqueue_args *uap)
{
union sigval sv;
sv.sival_ptr = uap->value;
return (kern_sigqueue(td, uap->pid, uap->signum, &sv));
}
int
kern_sigqueue(struct thread *td, pid_t pid, int signum, union sigval *value)
{
ksiginfo_t ksi;
struct proc *p;
int error;
if ((u_int)uap->signum > _SIG_MAXSIG)
if ((u_int)signum > _SIG_MAXSIG)
return (EINVAL);
/*
* Specification says sigqueue can only send signal to
* single process.
*/
if (uap->pid <= 0)
if (pid <= 0)
return (EINVAL);
if ((p = pfind(uap->pid)) == NULL) {
if ((p = zpfind(uap->pid)) == NULL)
if ((p = pfind(pid)) == NULL) {
if ((p = zpfind(pid)) == NULL)
return (ESRCH);
}
error = p_cansignal(td, p, uap->signum);
if (error == 0 && uap->signum != 0) {
error = p_cansignal(td, p, signum);
if (error == 0 && signum != 0) {
ksiginfo_init(&ksi);
ksi.ksi_flags = KSI_SIGQ;
ksi.ksi_signo = uap->signum;
ksi.ksi_signo = signum;
ksi.ksi_code = SI_QUEUE;
ksi.ksi_pid = td->td_proc->p_pid;
ksi.ksi_uid = td->td_ucred->cr_ruid;
ksi.ksi_value.sival_ptr = uap->value;
ksi.ksi_value = *value;
error = pksignal(p, ksi.ksi_signo, &ksi);
}
PROC_UNLOCK(p);

View File

@ -249,6 +249,8 @@ int kern_sigprocmask(struct thread *td, int how,
int kern_sigsuspend(struct thread *td, sigset_t mask);
int kern_sigtimedwait(struct thread *td, sigset_t waitset,
struct ksiginfo *ksi, struct timespec *timeout);
int kern_sigqueue(struct thread *td, pid_t pid, int signum,
union sigval *value);
int kern_socket(struct thread *td, int domain, int type, int protocol);
int kern_statat(struct thread *td, int flag, int fd, char *path,
enum uio_seg pathseg, struct stat *sbp,