summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-10-19 10:02:26 +0000
committerkib <kib@FreeBSD.org>2008-10-19 10:02:26 +0000
commit29ccf7d1668ab3c3e3e82c53dbf69d4c5a9be824 (patch)
treeb27837b90bdbe0e63b7ff72ce0c5c2b29bb7cbd5
parent40d90afbe6bf6ae24e4859c61cb929f3f0ccc441 (diff)
downloadFreeBSD-src-29ccf7d1668ab3c3e3e82c53dbf69d4c5a9be824.zip
FreeBSD-src-29ccf7d1668ab3c3e3e82c53dbf69d4c5a9be824.tar.gz
Correctly fill siginfo for the signals delivered by linux tkill/tgkill.
It is required for async cancellation to work. Fix PROC_LOCK leak in linux_tgkill when signal delivery attempt is made to not linux process. Do not call em_find(p, ...) with p unlocked. Move common code for linux_tkill() and linux_tgkill() into linux_do_tkill(). Change linux siginfo_t definition to match actual linux one. Extend uid fields to 4 bytes from 2. The extension does not change structure layout and is binary compatible with previous definition, because i386 is little endian, and each uid field has 2 byte padding after it. Reported by: Nicolas Joly <njoly pasteur fr> Submitted by: dchangin MFC after: 1 month
-rw-r--r--sys/amd64/linux32/linux.h29
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c4
-rw-r--r--sys/compat/linux/linux_signal.c113
-rw-r--r--sys/compat/linux/linux_signal.h3
-rw-r--r--sys/i386/linux/linux.h32
-rw-r--r--sys/i386/linux/linux_sysvec.c4
6 files changed, 132 insertions, 53 deletions
diff --git a/sys/amd64/linux32/linux.h b/sys/amd64/linux32/linux.h
index 0acdd68..2354864 100644
--- a/sys/amd64/linux32/linux.h
+++ b/sys/amd64/linux32/linux.h
@@ -86,6 +86,8 @@ typedef l_long l_suseconds_t;
typedef l_long l_time_t;
typedef l_uint l_uid_t;
typedef l_ushort l_uid16_t;
+typedef l_int l_timer_t;
+typedef l_int l_mqd_t;
typedef struct {
l_int val[2];
@@ -399,10 +401,10 @@ struct l_ucontext {
#define LINUX_SI_MAX_SIZE 128
#define LINUX_SI_PAD_SIZE ((LINUX_SI_MAX_SIZE/sizeof(l_int)) - 3)
-union l_sigval {
+typedef union l_sigval {
l_int sival_int;
l_uintptr_t sival_ptr;
-};
+} l_sigval_t;
typedef struct l_siginfo {
l_int lsi_signo;
@@ -413,23 +415,26 @@ typedef struct l_siginfo {
struct {
l_pid_t _pid;
- l_uid16_t _uid;
+ l_uid_t _uid;
} __packed _kill;
struct {
- l_uint _timer1;
- l_uint _timer2;
+ l_timer_t _tid;
+ l_int _overrun;
+ char _pad[sizeof(l_uid_t) - sizeof(l_int)];
+ l_sigval_t _sigval;
+ l_int _sys_private;
} __packed _timer;
struct {
l_pid_t _pid; /* sender's pid */
- l_uid16_t _uid; /* sender's uid */
- union l_sigval _sigval;
+ l_uid_t _uid; /* sender's uid */
+ l_sigval_t _sigval;
} __packed _rt;
struct {
l_pid_t _pid; /* which child */
- l_uid16_t _uid; /* sender's uid */
+ l_uid_t _uid; /* sender's uid */
l_int _status; /* exit code */
l_clock_t _utime;
l_clock_t _stime;
@@ -440,7 +445,7 @@ typedef struct l_siginfo {
} __packed _sigfault;
struct {
- l_int _band; /* POLL_IN,POLL_OUT,POLL_MSG */
+ l_long _band; /* POLL_IN,POLL_OUT,POLL_MSG */
l_int _fd;
} __packed _sigpoll;
} _sifields;
@@ -448,6 +453,9 @@ typedef struct l_siginfo {
#define lsi_pid _sifields._kill._pid
#define lsi_uid _sifields._kill._uid
+#define lsi_tid _sifields._timer._tid
+#define lsi_overrun _sifields._timer._overrun
+#define lsi_sys_private _sifields._timer._sys_private
#define lsi_status _sifields._sigchld._status
#define lsi_utime _sifields._sigchld._utime
#define lsi_stime _sifields._sigchld._stime
@@ -860,9 +868,6 @@ struct l_user_desc {
#define LINUX_CLOCK_REALTIME_HR 4
#define LINUX_CLOCK_MONOTONIC_HR 5
-typedef int l_timer_t;
-typedef int l_mqd_t;
-
#define LINUX_CLONE_VM 0x00000100
#define LINUX_CLONE_FS 0x00000200
#define LINUX_CLONE_FILES 0x00000400
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index 6a7aac7..e233700 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -334,9 +334,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
frame.sf_ucontext = PTROUT(&fp->sf_sc);
/* Fill in POSIX parts */
- frame.sf_si.lsi_signo = sig;
- frame.sf_si.lsi_code = code;
- frame.sf_si.lsi_addr = PTROUT(ksi->ksi_addr);
+ ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
/*
* Build the signal context to be used by sigreturn.
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
index d40d9d7..9bbc268 100644
--- a/sys/compat/linux/linux_signal.c
+++ b/sys/compat/linux/linux_signal.c
@@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
+#include <security/audit/audit.h>
+
#include "opt_compat.h"
#ifdef COMPAT_LINUX32
@@ -535,45 +537,75 @@ linux_kill(struct thread *td, struct linux_kill_args *args)
return (kill(td, &tmp));
}
-int
-linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
+static int
+linux_do_tkill(struct thread *td, l_int tgid, l_int pid, l_int signum)
{
- struct linux_emuldata *em;
- struct linux_kill_args ka;
+ struct proc *proc = td->td_proc;
+ struct linux_emuldata *em;
struct proc *p;
+ ksiginfo_t ksi;
+ int error;
-#ifdef DEBUG
- if (ldebug(tgkill))
- printf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig);
-#endif
-
- ka.pid = args->pid;
- ka.signum = args->sig;
+ AUDIT_ARG(signum, signum);
+ AUDIT_ARG(pid, pid);
- if (args->tgid == -1)
- return linux_kill(td, &ka);
+ /*
+ * Allow signal 0 as a means to check for privileges
+ */
+ if (!LINUX_SIG_VALID(signum) && signum != 0)
+ return (EINVAL);
- if ((p = pfind(args->pid)) == NULL)
- return ESRCH;
+ if (signum > 0 && signum <= LINUX_SIGTBLSZ)
+ signum = linux_to_bsd_signal[_SIG_IDX(signum)];
- if (p->p_sysent != &elf_linux_sysvec)
- return ESRCH;
+ if ((p = pfind(pid)) == NULL) {
+ if ((p = zpfind(pid)) == NULL)
+ return (ESRCH);
+ }
- PROC_UNLOCK(p);
+ AUDIT_ARG(process, p);
+ error = p_cansignal(td, p, signum);
+ if (error)
+ goto out;
+ error = ESRCH;
em = em_find(p, EMUL_DONTLOCK);
if (em == NULL) {
#ifdef DEBUG
- printf("emuldata not found in tgkill.\n");
+ printf("emuldata not found in do_tkill.\n");
#endif
- return ESRCH;
+ goto out;
}
+ if (tgid > 0 && em->shared->group_pid != tgid)
+ goto out;
+
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = signum;
+ ksi.ksi_code = LINUX_SI_TKILL;
+ ksi.ksi_errno = 0;
+ ksi.ksi_pid = proc->p_pid;
+ ksi.ksi_uid = proc->p_ucred->cr_ruid;
- if (em->shared->group_pid != args->tgid)
- return ESRCH;
+ error = tdsignal(p, NULL, ksi.ksi_signo, &ksi);
- return linux_kill(td, &ka);
+out:
+ PROC_UNLOCK(p);
+ return (error);
+}
+
+int
+linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
+{
+
+#ifdef DEBUG
+ if (ldebug(tgkill))
+ printf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig);
+#endif
+ if (args->pid <= 0 || args->tgid <=0)
+ return (EINVAL);
+
+ return (linux_do_tkill(td, args->tgid, args->pid, args->sig));
}
int
@@ -583,6 +615,39 @@ linux_tkill(struct thread *td, struct linux_tkill_args *args)
if (ldebug(tkill))
printf(ARGS(tkill, "%i, %i"), args->tid, args->sig);
#endif
+ if (args->tid <= 0)
+ return (EINVAL);
+
+ return (linux_do_tkill(td, 0, args->tid, args->sig));
+}
+
+void
+ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
+{
+
+ lsi->lsi_signo = sig;
+ lsi->lsi_code = ksi->ksi_code;
- return (linux_kill(td, (struct linux_kill_args *) args));
+ switch (sig) {
+ case LINUX_SIGPOLL:
+ /* XXX si_fd? */
+ lsi->lsi_band = ksi->ksi_band;
+ break;
+ case LINUX_SIGCHLD:
+ lsi->lsi_pid = ksi->ksi_pid;
+ lsi->lsi_uid = ksi->ksi_uid;
+ lsi->lsi_status = ksi->ksi_status;
+ break;
+ case LINUX_SIGBUS:
+ case LINUX_SIGILL:
+ case LINUX_SIGFPE:
+ case LINUX_SIGSEGV:
+ lsi->lsi_addr = PTROUT(ksi->ksi_addr);
+ break;
+ default:
+ /* XXX SI_TIMER etc... */
+ lsi->lsi_pid = ksi->ksi_pid;
+ lsi->lsi_uid = ksi->ksi_uid;
+ break;
+ }
}
diff --git a/sys/compat/linux/linux_signal.h b/sys/compat/linux/linux_signal.h
index 5f6d5bd..ba780e9 100644
--- a/sys/compat/linux/linux_signal.h
+++ b/sys/compat/linux/linux_signal.h
@@ -31,9 +31,12 @@
#ifndef _LINUX_SIGNAL_H_
#define _LINUX_SIGNAL_H_
+#define LINUX_SI_TKILL -6;
+
void linux_to_bsd_sigset(l_sigset_t *, sigset_t *);
void bsd_to_linux_sigset(sigset_t *, l_sigset_t *);
int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *);
+void ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig);
#define LINUX_SIG_VALID(sig) ((sig) <= LINUX_NSIG && (sig) > 0)
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h
index 4f2dbe9..6b11e84 100644
--- a/sys/i386/linux/linux.h
+++ b/sys/i386/linux/linux.h
@@ -80,6 +80,8 @@ typedef l_long l_suseconds_t;
typedef l_long l_time_t;
typedef l_uint l_uid_t;
typedef l_ushort l_uid16_t;
+typedef l_int l_timer_t;
+typedef l_int l_mqd_t;
typedef struct {
l_int val[2];
@@ -374,6 +376,11 @@ struct l_ucontext {
#define LINUX_SI_MAX_SIZE 128
#define LINUX_SI_PAD_SIZE ((LINUX_SI_MAX_SIZE/sizeof(l_int)) - 3)
+typedef union l_sigval {
+ l_int sival_int;
+ l_uintptr_t sival_ptr;
+} l_sigval_t;
+
typedef struct l_siginfo {
l_int lsi_signo;
l_int lsi_errno;
@@ -383,34 +390,37 @@ typedef struct l_siginfo {
struct {
l_pid_t _pid;
- l_uid16_t _uid;
+ l_uid_t _uid;
} _kill;
struct {
- l_uint _timer1;
- l_uint _timer2;
+ l_timer_t _tid;
+ l_int _overrun;
+ char _pad[sizeof(l_uid_t) - sizeof(l_int)];
+ l_sigval_t _sigval;
+ l_int _sys_private;
} _timer;
struct {
l_pid_t _pid; /* sender's pid */
- l_uid16_t _uid; /* sender's uid */
- union sigval _sigval;
+ l_uid_t _uid; /* sender's uid */
+ l_sigval_t _sigval;
} _rt;
struct {
l_pid_t _pid; /* which child */
- l_uid16_t _uid; /* sender's uid */
+ l_uid_t _uid; /* sender's uid */
l_int _status; /* exit code */
l_clock_t _utime;
l_clock_t _stime;
} _sigchld;
struct {
- void *_addr; /* Faulting insn/memory ref. */
+ l_uintptr_t _addr; /* Faulting insn/memory ref. */
} _sigfault;
struct {
- l_int _band; /* POLL_IN,POLL_OUT,POLL_MSG */
+ l_long _band; /* POLL_IN,POLL_OUT,POLL_MSG */
l_int _fd;
} _sigpoll;
} _sifields;
@@ -418,6 +428,9 @@ typedef struct l_siginfo {
#define lsi_pid _sifields._kill._pid
#define lsi_uid _sifields._kill._uid
+#define lsi_tid _sifields._timer._tid
+#define lsi_overrun _sifields._timer._overrun
+#define lsi_sys_private _sifields._timer._sys_private
#define lsi_status _sifields._sigchld._status
#define lsi_utime _sifields._sigchld._utime
#define lsi_stime _sifields._sigchld._stime
@@ -825,9 +838,6 @@ struct l_desc_struct {
#define LINUX_CLOCK_REALTIME_HR 4
#define LINUX_CLOCK_MONOTONIC_HR 5
-typedef int l_timer_t;
-typedef int l_mqd_t;
-
#define LINUX_CLONE_VM 0x00000100
#define LINUX_CLONE_FS 0x00000200
#define LINUX_CLONE_FILES 0x00000400
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 91f943d..a3acfc9 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -323,9 +323,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
frame.sf_ucontext = &fp->sf_sc;
/* Fill in POSIX parts */
- frame.sf_si.lsi_signo = sig;
- frame.sf_si.lsi_code = code;
- frame.sf_si.lsi_addr = ksi->ksi_addr;
+ ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
/*
* Build the signal context to be used by sigreturn.
OpenPOWER on IntegriCloud