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.
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to