From 1ea01fc9055fae058ce1589593fb8bfbeacb5418 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 19 Sep 2022 15:31:16 -0700 Subject: [PATCH] Fix pledge() thread killing semantics - tkill(tid, sig) should be allowed by stdio - tgkill(getpid(), tid, sig) should be allowed by stdio Fixes #628 --- libc/calls/pledge-linux.c | 20 +++++++++---------- test/libc/calls/pledge_test.c | 36 ++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/libc/calls/pledge-linux.c b/libc/calls/pledge-linux.c index 6fa80fc9e..dd7faa889 100644 --- a/libc/calls/pledge-linux.c +++ b/libc/calls/pledge-linux.c @@ -540,7 +540,8 @@ static const uint16_t kPledgeStdio[] = { __NR_linux_sigsuspend, // __NR_linux_sigpending, // __NR_linux_kill | SELF, // - __NR_linux_tkill | SELF, // + __NR_linux_tkill, // + __NR_linux_tgkill | SELF, // __NR_linux_socketpair, // __NR_linux_getrusage, // __NR_linux_times, // @@ -691,6 +692,7 @@ static const uint16_t kPledgeProc[] = { __NR_linux_vfork, // __NR_linux_clone | RESTRICT, // __NR_linux_kill, // + __NR_linux_tgkill, // __NR_linux_setsid, // __NR_linux_setpgid, // __NR_linux_prlimit, // @@ -707,8 +709,6 @@ static const uint16_t kPledgeProc[] = { __NR_linux_sched_setaffinity, // __NR_linux_sched_getparam, // __NR_linux_sched_setparam, // - __NR_linux_tkill, // - __NR_linux_tgkill, // }; static const uint16_t kPledgeId[] = { @@ -1028,15 +1028,15 @@ static privileged void AllowKillSelf(struct Filter *f) { AppendFilter(f, PLEDGE(fragment)); } -// The first argument of tkill() must be +// The first argument of tgkill() must be // -// - gettid() +// - getpid() // -static privileged void AllowTkillSelf(struct Filter *f) { +static privileged void AllowTgkillSelf(struct Filter *f) { struct sock_filter fragment[] = { - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_tkill, 0, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_tgkill, 0, 4), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, GetTid(), 0, 1), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, GetPid(), 0, 1), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)), }; @@ -1949,8 +1949,8 @@ static privileged void AppendPledge(struct Filter *f, // case __NR_linux_kill | SELF: AllowKillSelf(f); break; - case __NR_linux_tkill | SELF: - AllowTkillSelf(f); + case __NR_linux_tgkill | SELF: + AllowTgkillSelf(f); break; default: notpossible; diff --git a/test/libc/calls/pledge_test.c b/test/libc/calls/pledge_test.c index ecc6c566d..ed4a430e1 100644 --- a/test/libc/calls/pledge_test.c +++ b/test/libc/calls/pledge_test.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/mem/copyfd.internal.h" #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" #include "libc/calls/pledge.internal.h" @@ -26,11 +25,14 @@ #include "libc/calls/struct/flock.h" #include "libc/calls/struct/seccomp.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/stat.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" +#include "libc/mem/copyfd.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" @@ -53,6 +55,7 @@ #include "libc/sysv/consts/sock.h" #include "libc/sysv/consts/sol.h" #include "libc/testlib/ezbench.h" +#include "libc/testlib/subprocess.h" #include "libc/testlib/testlib.h" #include "libc/thread/spawn.h" #include "libc/time/time.h" @@ -143,6 +146,37 @@ TEST(pledge, withThreadMemory) { EXPECT_EQ(4, job[0]); // check result } +bool gotusr1; + +void OnUsr1(int sig) { + gotusr1 = true; +} + +int TgkillWorker(void *arg, int tid) { + sigset_t mask; + signal(SIGUSR1, OnUsr1); + sigemptyset(&mask); + ASSERT_SYS(EINTR, -1, sigsuspend(&mask)); + ASSERT_TRUE(gotusr1); + return 0; +} + +TEST(pledge, tgkill) { + // https://github.com/jart/cosmopolitan/issues/628 + if (!IsLinux()) return; + sigset_t mask; + struct spawn worker; + SPAWN(fork); + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &mask, 0); + ASSERT_SYS(0, 0, pledge("stdio", 0)); + ASSERT_SYS(0, 0, _spawn(TgkillWorker, 0, &worker)); + ASSERT_SYS(0, 0, tgkill(getpid(), worker.ptid, SIGUSR1)); + ASSERT_SYS(0, 0, _join(&worker)); + EXITS(0); +} + TEST(pledge, stdio_forbidsOpeningPasswd1) { if (!IsLinux()) return; int ws, pid;