Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Oct 2008 10:02:26 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r184058 - in head/sys: amd64/linux32 compat/linux i386/linux
Message-ID:  <200810191002.m9JA2Q5N040016@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sun Oct 19 10:02:26 2008
New Revision: 184058
URL: http://svn.freebsd.org/changeset/base/184058

Log:
  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

Modified:
  head/sys/amd64/linux32/linux.h
  head/sys/amd64/linux32/linux32_sysvec.c
  head/sys/compat/linux/linux_signal.c
  head/sys/compat/linux/linux_signal.h
  head/sys/i386/linux/linux.h
  head/sys/i386/linux/linux_sysvec.c

Modified: head/sys/amd64/linux32/linux.h
==============================================================================
--- head/sys/amd64/linux32/linux.h	Sun Oct 19 09:45:29 2008	(r184057)
+++ head/sys/amd64/linux32/linux.h	Sun Oct 19 10:02:26 2008	(r184058)
@@ -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

Modified: head/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- head/sys/amd64/linux32/linux32_sysvec.c	Sun Oct 19 09:45:29 2008	(r184057)
+++ head/sys/amd64/linux32/linux32_sysvec.c	Sun Oct 19 10:02:26 2008	(r184058)
@@ -334,9 +334,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo
 	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.

Modified: head/sys/compat/linux/linux_signal.c
==============================================================================
--- head/sys/compat/linux/linux_signal.c	Sun Oct 19 09:45:29 2008	(r184057)
+++ head/sys/compat/linux/linux_signal.c	Sun Oct 19 10:02:26 2008	(r184058)
@@ -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 lin
 	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 li
 	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;
+	}
 }

Modified: head/sys/compat/linux/linux_signal.h
==============================================================================
--- head/sys/compat/linux/linux_signal.h	Sun Oct 19 09:45:29 2008	(r184057)
+++ head/sys/compat/linux/linux_signal.h	Sun Oct 19 10:02:26 2008	(r184058)
@@ -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)
 

Modified: head/sys/i386/linux/linux.h
==============================================================================
--- head/sys/i386/linux/linux.h	Sun Oct 19 09:45:29 2008	(r184057)
+++ head/sys/i386/linux/linux.h	Sun Oct 19 10:02:26 2008	(r184058)
@@ -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

Modified: head/sys/i386/linux/linux_sysvec.c
==============================================================================
--- head/sys/i386/linux/linux_sysvec.c	Sun Oct 19 09:45:29 2008	(r184057)
+++ head/sys/i386/linux/linux_sysvec.c	Sun Oct 19 10:02:26 2008	(r184058)
@@ -323,9 +323,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo
 	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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200810191002.m9JA2Q5N040016>