Release pledge.com v1.6

This commit is contained in:
Justine Tunney 2022-08-10 08:11:05 -07:00
parent ae5d06dc53
commit 4e939d1761
5 changed files with 46 additions and 145 deletions

View file

@ -32,12 +32,6 @@
char testlib_enable_tmp_setup_teardown; char testlib_enable_tmp_setup_teardown;
void SetUpOnce(void) {
ASSERT_SYS(0, 0,
pledge("stdio rpath wpath cpath fattr proc exec prot_exec",
"stdio rpath wpath prot_exec"));
}
static textstartup void TestInit(int argc, char **argv) { static textstartup void TestInit(int argc, char **argv) {
int fd; int fd;
if (argc == 2 && !strcmp(argv[1], "boop")) { if (argc == 2 && !strcmp(argv[1], "boop")) {

View file

@ -604,7 +604,8 @@ TEST(pledge, threadWithLocks_canCodeMorph) {
int ws, pid; int ws, pid;
// not sure how this works on OpenBSD but it works! // not sure how this works on OpenBSD but it works!
if (!fork()) { if (!fork()) {
ASSERT_SYS(0, 0, pledge("stdio prot_exec", 0)); __enable_threads();
ASSERT_SYS(0, 0, pledge("stdio", 0));
ASSERT_SYS(0, 0, _spawn(LockWorker, 0, &worker)); ASSERT_SYS(0, 0, _spawn(LockWorker, 0, &worker));
ASSERT_SYS(0, 0, _join(&worker)); ASSERT_SYS(0, 0, _join(&worker));
_Exit(0); _Exit(0);

View file

@ -1,129 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/intrin/kprintf.h"
#include "libc/mem/io.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
STATIC_YOINK("zip_uri_support");
STATIC_YOINK("apetest.com");
STATIC_YOINK("apetest2.com");
char testlib_enable_tmp_setup_teardown_once;
void Extract(const char *from, const char *to, int mode) {
ASSERT_SYS(0, 3, open(from, O_RDONLY));
ASSERT_SYS(0, 4, creat(to, mode));
ASSERT_NE(-1, _copyfd(3, 4, -1));
EXPECT_SYS(0, 0, close(4));
EXPECT_SYS(0, 0, close(3));
}
void SetUpOnce(void) {
ASSERT_SYS(0, 0,
pledge("stdio rpath wpath cpath tty proc exec prot_exec",
"stdio rpath prot_exec"));
// nothing to do if we're using elf
if (~SUPPORT_VECTOR & (WINDOWS | XNU)) {
exit(0);
}
ASSERT_SYS(0, 0, mkdir("bin", 0755));
Extract("/zip/apetest.com", "bin/apetest.com", 0755);
Extract("/zip/apetest2.com", "bin/apetest2.com", 0755);
// force the extraction of ape payload
// if system does not have binfmt_misc
ASSERT_SYS(0, 0, mkdir("tmp", 0755));
setenv("TMPDIR", "tmp", true);
}
void RunApeTest(const char *path) {
size_t n;
ssize_t rc, got;
char buf[512] = {0};
sigset_t chldmask, savemask;
int i, pid, fdin, wstatus, pfds[2];
struct sigaction ignore, saveint, savequit, savepipe;
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
sigaction(SIGPIPE, &ignore, &savepipe);
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
ASSERT_SYS(0, 0, pipe2(pfds, O_CLOEXEC));
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
__strace = 0;
__ftrace = 0;
close(1);
dup(pfds[1]);
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigaction(SIGPIPE, &savepipe, 0);
sigprocmask(SIG_SETMASK, &savemask, 0);
execv(path, (char *const[]){path, 0});
_Exit(127);
}
close(pfds[1]);
EXPECT_SYS(0, 8, read(pfds[0], buf, sizeof(buf)));
EXPECT_STREQ("success\n", buf);
close(pfds[0]);
EXPECT_NE(-1, wait(&wstatus));
EXPECT_TRUE(WIFEXITED(wstatus));
EXPECT_EQ(0, WEXITSTATUS(wstatus));
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigaction(SIGPIPE, &savepipe, 0);
sigprocmask(SIG_SETMASK, &savemask, 0);
EXPECT_SYS(0, 3, open(path, O_RDONLY));
EXPECT_SYS(0, 6, read(3, buf, 6));
EXPECT_SYS(0, 0, close(3));
EXPECT_STREQN("MZqFpD", buf, 6);
}
TEST(ape, noAccidentalQuotesInMasterBootRecord) {
int i, quotes = 0;
char buf[512] = {0};
EXPECT_SYS(0, 3, open("bin/apetest.com", O_RDONLY));
EXPECT_SYS(0, 512, read(3, buf, 512));
EXPECT_SYS(0, 0, close(3));
for (i = 0; i < 512; ++i) {
if (buf[i] == '\'') {
++quotes;
}
}
EXPECT_EQ(1, quotes);
}
TEST(apeNoModifySelf, runsWithoutModifyingSelf) {
RunApeTest("bin/apetest.com");
}
TEST(apeCopySelf, runsWithoutModifyingSelf) {
RunApeTest("bin/apetest2.com");
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/spawn.h" #include "libc/stdio/spawn.h"
@ -31,17 +32,22 @@
void SetUpOnce(void) { void SetUpOnce(void) {
__enable_threads(); __enable_threads();
ASSERT_SYS(0, 0, }
pledge("stdio rpath wpath cpath proc exec prot_exec",
"stdio rpath wpath cpath prot_exec")); __attribute__((__constructor__)) static void init(void) {
if (atoi(nulltoempty(getenv("THE_DOGE"))) == 42) {
exit(42);
}
} }
TEST(spawn, test) { TEST(spawn, test) {
if (atoi(nulltoempty(getenv("THE_DOGE"))) == 42) {
exit(42);
}
int rc, ws, pid; int rc, ws, pid;
char *prog = GetProgramExecutableName(); char *prog = GetProgramExecutableName();
char *args[] = {program_invocation_name, NULL}; char *args[] = {program_invocation_name, NULL};
char *envs[] = {"THE_DOGE=42", NULL}; char *envs[] = {"THE_DOGE=42", NULL};
if (atoi(nulltoempty(getenv("THE_DOGE"))) == 42) exit(42);
EXPECT_EQ(0, posix_spawn(&pid, prog, NULL, NULL, args, envs)); EXPECT_EQ(0, posix_spawn(&pid, prog, NULL, NULL, args, envs));
EXPECT_NE(-1, waitpid(pid, &ws, 0)); EXPECT_NE(-1, waitpid(pid, &ws, 0));
EXPECT_TRUE(WIFEXITED(ws)); EXPECT_TRUE(WIFEXITED(ws));

View file

@ -28,6 +28,7 @@
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/struct/sysinfo.h" #include "libc/calls/struct/sysinfo.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/elf/def.h" #include "libc/elf/def.h"
#include "libc/elf/struct/ehdr.h" #include "libc/elf/struct/ehdr.h"
@ -77,6 +78,7 @@ usage: pledge.com [-hnN] PROG ARGS...\n\
-u UID call setuid()\n\ -u UID call setuid()\n\
-c PATH call chroot()\n\ -c PATH call chroot()\n\
-v [PERM:]PATH call unveil(PATH, PERM[rwxc])\n\ -v [PERM:]PATH call unveil(PATH, PERM[rwxc])\n\
-V disable unveiling (only pledge)\n\
-k kill process rather than eperm'ing\n\ -k kill process rather than eperm'ing\n\
-n set maximum niceness\n\ -n set maximum niceness\n\
-D don't drop capabilities\n\ -D don't drop capabilities\n\
@ -85,6 +87,8 @@ usage: pledge.com [-hnN] PROG ARGS...\n\
-M BYTES set virtual memory limit [default: 4gb]\n\ -M BYTES set virtual memory limit [default: 4gb]\n\
-P PROCS set process limit [default: GetCpuCount()*2]\n\ -P PROCS set process limit [default: GetCpuCount()*2]\n\
-F BYTES set individual file size limit [default: 4gb]\n\ -F BYTES set individual file size limit [default: 4gb]\n\
-T pledge exits 0 if pledge() is supported by host system\n\
-T unveil exits 0 if unveil() is supported by host system\n\
-p PLEDGE may contain any of following separated by spaces\n\ -p PLEDGE may contain any of following separated by spaces\n\
- stdio: allow stdio and benign system calls\n\ - stdio: allow stdio and benign system calls\n\
- rpath: read-only path ops\n\ - rpath: read-only path ops\n\
@ -106,7 +110,7 @@ usage: pledge.com [-hnN] PROG ARGS...\n\
- vminfo: allows /proc/stat, /proc/self/maps, etc.\n\ - vminfo: allows /proc/stat, /proc/self/maps, etc.\n\
- tmppath: allows /tmp, $TMPPATH, lstat, unlink\n\ - tmppath: allows /tmp, $TMPPATH, lstat, unlink\n\
\n\ \n\
pledge.com v1.5\n\ pledge.com v1.6\n\
copyright 2022 justine alexandra roberts tunney\n\ copyright 2022 justine alexandra roberts tunney\n\
https://twitter.com/justinetunney\n\ https://twitter.com/justinetunney\n\
https://linkedin.com/in/jtunney\n\ https://linkedin.com/in/jtunney\n\
@ -133,6 +137,8 @@ long g_fszquota;
long g_memquota; long g_memquota;
long g_proquota; long g_proquota;
long g_dontdrop; long g_dontdrop;
long g_dontunveil;
const char *g_test;
const char *g_chroot; const char *g_chroot;
const char *g_promises; const char *g_promises;
char dsopath[PATH_MAX]; char dsopath[PATH_MAX];
@ -151,7 +157,7 @@ static void GetOpts(int argc, char *argv[]) {
g_proquota = GetCpuCount() * 100; g_proquota = GetCpuCount() * 100;
g_memquota = 4L * 1024 * 1024 * 1024; g_memquota = 4L * 1024 * 1024 * 1024;
if (!sysinfo(&si)) g_memquota = si.totalram; if (!sysinfo(&si)) g_memquota = si.totalram;
while ((opt = getopt(argc, argv, "hnkNp:u:g:c:C:D:P:M:F:v:")) != -1) { while ((opt = getopt(argc, argv, "hnkNVT:p:u:g:c:C:D:P:M:F:v:")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
g_nice = true; g_nice = true;
@ -165,6 +171,12 @@ static void GetOpts(int argc, char *argv[]) {
case 'D': case 'D':
g_dontdrop = true; g_dontdrop = true;
break; break;
case 'V':
g_dontunveil = true;
break;
case 'T':
g_test = optarg;
break;
case 'c': case 'c':
g_chroot = optarg; g_chroot = optarg;
break; break;
@ -390,9 +402,8 @@ void MakeProcessNice(void) {
void ApplyFilesystemPolicy(unsigned long ipromises) { void ApplyFilesystemPolicy(unsigned long ipromises) {
const char *p; const char *p;
if (!SupportsLandlock()) { if (g_dontunveil) return;
return; if (!SupportsLandlock()) return;
}
Unveil(prog, "rx"); Unveil(prog, "rx");
@ -564,6 +575,24 @@ int main(int argc, char *argv[]) {
// parse flags // parse flags
GetOpts(argc, argv); GetOpts(argc, argv);
if (g_test) {
if (!strcmp(g_test, "pledge")) {
if (IsOpenbsd() || (IsLinux() && __is_linux_2_6_23())) {
exit(0);
} else {
exit(1);
}
}
if (!strcmp(g_test, "unveil")) {
if (IsOpenbsd() || (IsLinux() && SupportsLandlock())) {
exit(0);
} else {
exit(1);
}
}
kprintf("error: unknown test: %s\n", g_test);
exit(2);
}
if (optind == argc) { if (optind == argc) {
kprintf("error: too few args\n"); kprintf("error: too few args\n");
write(2, USAGE, sizeof(USAGE) - 1); write(2, USAGE, sizeof(USAGE) - 1);