summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrooks <brooks@FreeBSD.org>2017-05-12 17:40:34 +0000
committerbrooks <brooks@FreeBSD.org>2017-05-12 17:40:34 +0000
commit4d2f018c82bbae44270cd376e30c08b4f6c02b77 (patch)
tree0f8e0daf59a1e57f305f0d84eba8c812529fb7e6
parent2d1b658f1483422dc496ae5fe3392b5d11b7715b (diff)
downloadFreeBSD-src-4d2f018c82bbae44270cd376e30c08b4f6c02b77.zip
FreeBSD-src-4d2f018c82bbae44270cd376e30c08b4f6c02b77.tar.gz
MFC r317845-r317846
r317845: 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 Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D10605 r317846: Regen post r317845. MFC with: r317845 Sponsored by: DARPA, AFRL
-rw-r--r--lib/libc/sys/sigqueue.218
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c26
-rw-r--r--sys/compat/freebsd32/freebsd32_proto.h7
-rw-r--r--sys/compat/freebsd32/freebsd32_syscall.h2
-rw-r--r--sys/compat/freebsd32/freebsd32_syscalls.c2
-rw-r--r--sys/compat/freebsd32/freebsd32_sysent.c2
-rw-r--r--sys/compat/freebsd32/freebsd32_systrace_args.c12
-rw-r--r--sys/compat/freebsd32/syscalls.master4
-rw-r--r--sys/kern/kern_sig.c26
-rw-r--r--sys/sys/syscallsubr.h2
10 files changed, 80 insertions, 21 deletions
diff --git a/lib/libc/sys/sigqueue.2 b/lib/libc/sys/sigqueue.2
index 04e101b..8377c67 100644
--- a/lib/libc/sys/sigqueue.2
+++ b/lib/libc/sys/sigqueue.2
@@ -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.
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 08a072f..a8e69b7 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -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)
{
diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h
index a41063f..1620e59 100644
--- a/sys/compat/freebsd32/freebsd32_proto.h
+++ b/sys/compat/freebsd32/freebsd32_proto.h
@@ -382,6 +382,11 @@ struct freebsd32_thr_new_args {
char param_l_[PADL_(struct thr_param32 *)]; struct thr_param32 * param; char param_r_[PADR_(struct thr_param32 *)];
char param_size_l_[PADL_(int)]; int param_size; char param_size_r_[PADR_(int)];
};
+struct freebsd32_sigqueue_args {
+ char pid_l_[PADL_(pid_t)]; pid_t pid; char pid_r_[PADR_(pid_t)];
+ char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)];
+ char value_l_[PADL_(int)]; int value; char value_r_[PADR_(int)];
+};
struct freebsd32_kmq_open_args {
char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
@@ -764,6 +769,7 @@ int freebsd32_ksem_timedwait(struct thread *, struct freebsd32_ksem_timedwait_ar
int freebsd32_thr_suspend(struct thread *, struct freebsd32_thr_suspend_args *);
int freebsd32_umtx_op(struct thread *, struct freebsd32_umtx_op_args *);
int freebsd32_thr_new(struct thread *, struct freebsd32_thr_new_args *);
+int freebsd32_sigqueue(struct thread *, struct freebsd32_sigqueue_args *);
int freebsd32_kmq_open(struct thread *, struct freebsd32_kmq_open_args *);
int freebsd32_kmq_setattr(struct thread *, struct freebsd32_kmq_setattr_args *);
int freebsd32_kmq_timedreceive(struct thread *, struct freebsd32_kmq_timedreceive_args *);
@@ -1230,6 +1236,7 @@ int freebsd10_freebsd32_pipe(struct thread *, struct freebsd10_freebsd32_pipe_ar
#define FREEBSD32_SYS_AUE_freebsd32_thr_suspend AUE_NULL
#define FREEBSD32_SYS_AUE_freebsd32_umtx_op AUE_NULL
#define FREEBSD32_SYS_AUE_freebsd32_thr_new AUE_NULL
+#define FREEBSD32_SYS_AUE_freebsd32_sigqueue AUE_NULL
#define FREEBSD32_SYS_AUE_freebsd32_kmq_open AUE_NULL
#define FREEBSD32_SYS_AUE_freebsd32_kmq_setattr AUE_NULL
#define FREEBSD32_SYS_AUE_freebsd32_kmq_timedreceive AUE_NULL
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
index 6b06353..1445a19 100644
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -358,7 +358,7 @@
#define FREEBSD32_SYS_auditctl 453
#define FREEBSD32_SYS_freebsd32_umtx_op 454
#define FREEBSD32_SYS_freebsd32_thr_new 455
-#define FREEBSD32_SYS_sigqueue 456
+#define FREEBSD32_SYS_freebsd32_sigqueue 456
#define FREEBSD32_SYS_freebsd32_kmq_open 457
#define FREEBSD32_SYS_freebsd32_kmq_setattr 458
#define FREEBSD32_SYS_freebsd32_kmq_timedreceive 459
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
index 9ffbf2c..40edf40 100644
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -465,7 +465,7 @@ const char *freebsd32_syscallnames[] = {
"auditctl", /* 453 = auditctl */
"freebsd32_umtx_op", /* 454 = freebsd32_umtx_op */
"freebsd32_thr_new", /* 455 = freebsd32_thr_new */
- "sigqueue", /* 456 = sigqueue */
+ "freebsd32_sigqueue", /* 456 = freebsd32_sigqueue */
"freebsd32_kmq_open", /* 457 = freebsd32_kmq_open */
"freebsd32_kmq_setattr", /* 458 = freebsd32_kmq_setattr */
"freebsd32_kmq_timedreceive", /* 459 = freebsd32_kmq_timedreceive */
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
index a8b207f..f8cbdf5 100644
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -508,7 +508,7 @@ struct sysent freebsd32_sysent[] = {
{ AS(auditctl_args), (sy_call_t *)sys_auditctl, AUE_AUDITCTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 453 = auditctl */
{ AS(freebsd32_umtx_op_args), (sy_call_t *)freebsd32_umtx_op, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 454 = freebsd32_umtx_op */
{ AS(freebsd32_thr_new_args), (sy_call_t *)freebsd32_thr_new, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 455 = freebsd32_thr_new */
- { AS(sigqueue_args), (sy_call_t *)sys_sigqueue, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 456 = sigqueue */
+ { AS(freebsd32_sigqueue_args), (sy_call_t *)freebsd32_sigqueue, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 456 = freebsd32_sigqueue */
{ AS(freebsd32_kmq_open_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 457 = freebsd32_kmq_open */
{ AS(freebsd32_kmq_setattr_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_ABSENT }, /* 458 = freebsd32_kmq_setattr */
{ AS(freebsd32_kmq_timedreceive_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_ABSENT }, /* 459 = freebsd32_kmq_timedreceive */
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
index 002d4a2..85d3486 100644
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -2364,12 +2364,12 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 2;
break;
}
- /* sigqueue */
+ /* freebsd32_sigqueue */
case 456: {
- struct sigqueue_args *p = params;
+ struct freebsd32_sigqueue_args *p = params;
iarg[0] = p->pid; /* pid_t */
iarg[1] = p->signum; /* int */
- uarg[2] = (intptr_t) p->value; /* void * */
+ iarg[2] = p->value; /* int */
*n_args = 3;
break;
}
@@ -7155,7 +7155,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
- /* sigqueue */
+ /* freebsd32_sigqueue */
case 456:
switch(ndx) {
case 0:
@@ -7165,7 +7165,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 2:
- p = "void *";
+ p = "int";
break;
default:
break;
@@ -10335,7 +10335,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
- /* sigqueue */
+ /* freebsd32_sigqueue */
case 456:
if (ndx == 0 || ndx == 1)
p = "int";
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index d9afd24..91e3066 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -820,8 +820,8 @@
455 AUE_NULL 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_NULL NOSTD { int freebsd32_kmq_open( \
const char *path, int flags, mode_t mode, \
const struct mq_attr32 *attr); }
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index fc3ab29..a3ff180 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1862,33 +1862,43 @@ struct sigqueue_args {
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);
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 16af617..88b6c95 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -252,6 +252,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,
OpenPOWER on IntegriCloud