diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c index ff44a29eb46..23357cd2701 100644 --- a/sys/i386/linux/linux_machdep.c +++ b/sys/i386/linux/linux_machdep.c @@ -314,6 +314,9 @@ linux_vfork(struct thread *td, struct linux_vfork_args *args) #define CLONE_FILES 0x400 #define CLONE_SIGHAND 0x800 #define CLONE_PID 0x1000 +#define CLONE_THREAD 0x10000 + +#define THREADING_FLAGS (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND) int linux_clone(struct thread *td, struct linux_clone_args *args) @@ -349,6 +352,22 @@ linux_clone(struct thread *td, struct linux_clone_args *args) if (!(args->flags & CLONE_FILES)) ff |= RFFDG; + /* + * Attempt to detect when linux_clone(2) is used for creating + * kernel threads. Unfortunately despite the existence of the + * CLONE_THREAD flag, version of linuxthreads package used in + * most popular distros as of beginning of 2005 doesn't make + * any use of it. Therefore, this detection relay fully on + * empirical observation that linuxthreads sets certain + * combination of flags, so that we can make more or less + * precise detection and notify the FreeBSD kernel that several + * processes are in fact part of the same threading group, so + * that special treatment is necessary for signal delivery + * between those processes and fd locking. + */ + if ((args->flags & 0xffffff00) == THREADING_FLAGS) + ff |= RFTHREAD; + error = fork1(td, ff, 0, &p2); if (error) return (error); diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 38b904282ac..9c6cd09c68c 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -1523,6 +1523,18 @@ p_cansignal(struct thread *td, struct proc *p, int signum) /* XXX: This will require an additional lock of some sort. */ if (signum == SIGCONT && td->td_proc->p_session == p->p_session) return (0); + /* + * Some compat layers use SIGTHR for communications between + * different kernel threads of the same process, so that + * they are expecting that it's always possible to deliver + * it, even for suid applications where cr_cansignal() can + * deny such ability for security consideration. It should be + * pretty safe to do since the only way to create two processes + * with the same p_leader is via rfork(2). + */ + if (signum == SIGTHR && td->td_proc->p_leader != NULL && + td->td_proc->p_leader == p->p_leader) + return (0); return (cr_cansignal(td->td_ucred, p, signum)); }