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
This commit is contained in:
parent
40d90afbe6
commit
29ccf7d166
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
static int
|
||||
linux_do_tkill(struct thread *td, l_int tgid, l_int pid, l_int signum)
|
||||
{
|
||||
struct proc *proc = td->td_proc;
|
||||
struct linux_emuldata *em;
|
||||
struct proc *p;
|
||||
ksiginfo_t ksi;
|
||||
int error;
|
||||
|
||||
AUDIT_ARG(signum, signum);
|
||||
AUDIT_ARG(pid, pid);
|
||||
|
||||
/*
|
||||
* Allow signal 0 as a means to check for privileges
|
||||
*/
|
||||
if (!LINUX_SIG_VALID(signum) && signum != 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (signum > 0 && signum <= LINUX_SIGTBLSZ)
|
||||
signum = linux_to_bsd_signal[_SIG_IDX(signum)];
|
||||
|
||||
if ((p = pfind(pid)) == NULL) {
|
||||
if ((p = zpfind(pid)) == NULL)
|
||||
return (ESRCH);
|
||||
}
|
||||
|
||||
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 do_tkill.\n");
|
||||
#endif
|
||||
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;
|
||||
|
||||
error = tdsignal(p, NULL, ksi.ksi_signo, &ksi);
|
||||
|
||||
out:
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
|
||||
{
|
||||
struct linux_emuldata *em;
|
||||
struct linux_kill_args ka;
|
||||
struct proc *p;
|
||||
|
||||
#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);
|
||||
|
||||
ka.pid = args->pid;
|
||||
ka.signum = args->sig;
|
||||
|
||||
if (args->tgid == -1)
|
||||
return linux_kill(td, &ka);
|
||||
|
||||
if ((p = pfind(args->pid)) == NULL)
|
||||
return ESRCH;
|
||||
|
||||
if (p->p_sysent != &elf_linux_sysvec)
|
||||
return ESRCH;
|
||||
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
em = em_find(p, EMUL_DONTLOCK);
|
||||
|
||||
if (em == NULL) {
|
||||
#ifdef DEBUG
|
||||
printf("emuldata not found in tgkill.\n");
|
||||
#endif
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
if (em->shared->group_pid != args->tgid)
|
||||
return ESRCH;
|
||||
|
||||
return linux_kill(td, &ka);
|
||||
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_kill(td, (struct linux_kill_args *) args));
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user