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:
Konstantin Belousov 2008-10-19 10:02:26 +00:00
parent 4f1fb109f9
commit aa8b201112
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=184058
6 changed files with 139 additions and 60 deletions

View file

@ -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

View file

@ -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.

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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

View file

@ -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.