Make some touchups

This commit is contained in:
Justine Tunney 2022-07-15 18:07:34 -07:00
parent 6c49e36537
commit 2e3958c6dc
11 changed files with 161 additions and 63 deletions

View file

@ -47,12 +47,22 @@
* The `policy` must have one of: * The `policy` must have one of:
* *
* - `SCHED_OTHER` (or `SCHED_NORMAL`) for the default policy * - `SCHED_OTHER` (or `SCHED_NORMAL`) for the default policy
*
* - `SCHED_RR` for real-time round-robin scheduling * - `SCHED_RR` for real-time round-robin scheduling
*
* - `SCHED_FIFO` for real-time first-in first-out scheduling * - `SCHED_FIFO` for real-time first-in first-out scheduling
*
* - `SCHED_BATCH` for "batch" style execution of processes if * - `SCHED_BATCH` for "batch" style execution of processes if
* supported (Linux), otherwise it's treated as `SCHED_OTHER` * supported (Linux), otherwise it's treated as `SCHED_OTHER`
* - `SCHED_IDLE` for running very low priority background jobs *
* if it's supported (Linux), otherwise this is `SCHED_OTHER` * - `SCHED_IDLE` for running very low priority background jobs if
* it's supported (Linux), otherwise this is `SCHED_OTHER`.
* Pledging away scheduling privilege is permanent for your
* process; if a subsequent attempt is made to restore the
* `SCHED_OTHER` policy then this system call will `EPERM` (but on
* older kernels like RHEL7 this isn't the case). This policy
* isn't available on old Linux kernels like RHEL5, where it'll
* raise `EINVAL`.
* *
* The `policy` may optionally bitwise-or any one of: * The `policy` may optionally bitwise-or any one of:
* *
@ -65,7 +75,9 @@
* greater than or equal to sched_get_priority_min(policy) and less * greater than or equal to sched_get_priority_min(policy) and less
* than or equal to sched_get_priority_max(policy). Linux allows the * than or equal to sched_get_priority_max(policy). Linux allows the
* static priority range 1 to 99 for the `SCHED_FIFO` and `SCHED_RR` * static priority range 1 to 99 for the `SCHED_FIFO` and `SCHED_RR`
* policies, and the priority 0 for the remaining policies. * policies, and the priority 0 is used for the remaining policies.
* You should still consider calling the function, because on NetBSD
* the correct priority might be -1.
* *
* @return the former scheduling policy of the specified process. If * @return the former scheduling policy of the specified process. If
* this function fails, then the scheduling policy is not changed, * this function fails, then the scheduling policy is not changed,

21
libc/intrin/promises.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- 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/intrin/promises.internal.h"
unsigned long __promises;

View file

@ -0,0 +1,33 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_PROMISES_H_
#define COSMOPOLITAN_LIBC_INTRIN_PROMISES_H_
#define PROMISE_DEFAULT 0
#define PROMISE_STDIO 1
#define PROMISE_RPATH 2
#define PROMISE_WPATH 3
#define PROMISE_CPATH 4
#define PROMISE_DPATH 5
#define PROMISE_FLOCK 6
#define PROMISE_FATTR 7
#define PROMISE_INET 8
#define PROMISE_UNIX 9
#define PROMISE_DNS 10
#define PROMISE_TTY 11
#define PROMISE_RECVFD 12
#define PROMISE_PROC 13
#define PROMISE_THREAD 14
#define PROMISE_EXEC 15
#define PROMISE_EXECNATIVE 16
#define PROMISE_ID 17
#define PROMISE_MAX 17
#define PLEDGED(x) (~__promises & (1L << PROMISE_##x))
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
hidden extern unsigned long __promises;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_PROMISES_H_ */

View file

@ -23,6 +23,7 @@
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/promises.internal.h"
#include "libc/log/color.internal.h" #include "libc/log/color.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
@ -47,8 +48,7 @@ static union metatermios __oldtermios;
static textstartup void __oldtermios_init() { static textstartup void __oldtermios_init() {
int e; int e;
e = errno; e = errno;
if (!IsOpenbsd() && // avoid pledge(tty) if (PLEDGED(TTY) && sys_ioctl(0, TCGETS, &__oldtermios) != -1) {
sys_ioctl(0, TCGETS, &__oldtermios) != -1) {
__isrestorable = true; __isrestorable = true;
} }
errno = e; errno = e;
@ -60,7 +60,7 @@ const void *const __oldtermios_ctor[] initarray = {
void __restore_tty(void) { void __restore_tty(void) {
int e; int e;
if (__isrestorable && !__isworker && !__nocolor) { if (__isrestorable && PLEDGED(TTY) && !__isworker && !__nocolor) {
e = errno; e = errno;
sys_write(0, ANSI_RESTORE, __strlen(ANSI_RESTORE)); sys_write(0, ANSI_RESTORE, __strlen(ANSI_RESTORE));
sys_ioctl(0, TCSETSF, &__oldtermios); sys_ioctl(0, TCSETSF, &__oldtermios);

View file

@ -51,10 +51,14 @@ relegated void __check_fail(const char *suffix, const char *opstr,
__start_fatal(file, line); __start_fatal(file, line);
__stpcpy(hostname, "unknown"); __stpcpy(hostname, "unknown");
gethostname(hostname, sizeof(hostname)); gethostname(hostname, sizeof(hostname));
kprintf("check failed on %s pid %d\n", hostname, getpid()); kprintf("check failed on %s pid %d\n"
kprintf("\tCHECK_%^s(%s, %s);\n", suffix, wantstr, gotstr); "\tCHECK_%^s(%s, %s);\n"
kprintf("\t\t → %p (%s)\n", want, wantstr); "\t\t → %p (%s)\n"
kprintf("\t\t%s %p (%s)\n", opstr, got, gotstr); "\t\t%s %p (%s)\n", //
hostname, getpid(), //
suffix, wantstr, gotstr, //
want, wantstr, //
opstr, got, gotstr);
if (!isempty(fmt)) { if (!isempty(fmt)) {
kprintf("\t"); kprintf("\t");
va_start(va, fmt); va_start(va, fmt);

View file

@ -26,6 +26,7 @@
#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
@ -296,7 +297,7 @@ static const uint16_t kPledgeLinuxExec[] = {
__NR_linux_openat | READONLY, // __NR_linux_openat | READONLY, //
}; };
static const uint16_t kPledgeLinuxExecnative[] = { static const uint16_t kPledgeLinuxExec2[] = {
__NR_linux_execve, // __NR_linux_execve, //
__NR_linux_execveat, // __NR_linux_execveat, //
}; };
@ -306,25 +307,25 @@ static const struct Pledges {
const uint16_t *syscalls; const uint16_t *syscalls;
const size_t len; const size_t len;
} kPledgeLinux[] = { } kPledgeLinux[] = {
{"default", PLEDGE(kPledgeLinuxDefault)}, // [PROMISE_DEFAULT] = {"default", PLEDGE(kPledgeLinuxDefault)}, //
{"stdio", PLEDGE(kPledgeLinuxStdio)}, // [PROMISE_STDIO] = {"stdio", PLEDGE(kPledgeLinuxStdio)}, //
{"rpath", PLEDGE(kPledgeLinuxRpath)}, // [PROMISE_RPATH] = {"rpath", PLEDGE(kPledgeLinuxRpath)}, //
{"wpath", PLEDGE(kPledgeLinuxWpath)}, // [PROMISE_WPATH] = {"wpath", PLEDGE(kPledgeLinuxWpath)}, //
{"cpath", PLEDGE(kPledgeLinuxCpath)}, // [PROMISE_CPATH] = {"cpath", PLEDGE(kPledgeLinuxCpath)}, //
{"dpath", PLEDGE(kPledgeLinuxDpath)}, // [PROMISE_DPATH] = {"dpath", PLEDGE(kPledgeLinuxDpath)}, //
{"flock", PLEDGE(kPledgeLinuxFlock)}, // [PROMISE_FLOCK] = {"flock", PLEDGE(kPledgeLinuxFlock)}, //
{"fattr", PLEDGE(kPledgeLinuxFattr)}, // [PROMISE_FATTR] = {"fattr", PLEDGE(kPledgeLinuxFattr)}, //
{"inet", PLEDGE(kPledgeLinuxInet)}, // [PROMISE_INET] = {"inet", PLEDGE(kPledgeLinuxInet)}, //
{"unix", PLEDGE(kPledgeLinuxUnix)}, // [PROMISE_UNIX] = {"unix", PLEDGE(kPledgeLinuxUnix)}, //
{"dns", PLEDGE(kPledgeLinuxDns)}, // [PROMISE_DNS] = {"dns", PLEDGE(kPledgeLinuxDns)}, //
{"tty", PLEDGE(kPledgeLinuxTty)}, // [PROMISE_TTY] = {"tty", PLEDGE(kPledgeLinuxTty)}, //
{"recvfd", PLEDGE(kPledgeLinuxRecvfd)}, // [PROMISE_RECVFD] = {"recvfd", PLEDGE(kPledgeLinuxRecvfd)}, //
{"proc", PLEDGE(kPledgeLinuxProc)}, // [PROMISE_PROC] = {"proc", PLEDGE(kPledgeLinuxProc)}, //
{"thread", PLEDGE(kPledgeLinuxThread)}, // [PROMISE_THREAD] = {"thread", PLEDGE(kPledgeLinuxThread)}, //
{"exec", PLEDGE(kPledgeLinuxExec)}, // [PROMISE_EXEC] = {"exec", PLEDGE(kPledgeLinuxExec)}, //
{"execnative", PLEDGE(kPledgeLinuxExecnative)}, // [PROMISE_EXECNATIVE] = {"execnative", PLEDGE(kPledgeLinuxExec2)}, //
{"id", PLEDGE(kPledgeLinuxId)}, // [PROMISE_ID] = {"id", PLEDGE(kPledgeLinuxId)}, //
{0}, // [PROMISE_MAX + 1] = {0}, //
}; };
static const struct sock_filter kFilterStart[] = { static const struct sock_filter kFilterStart[] = {
@ -949,8 +950,8 @@ static bool AllowFchmodat(struct Filter *f) {
return AppendFilter(f, PLEDGE(fragment)); return AppendFilter(f, PLEDGE(fragment));
} }
static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len, static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len, bool needmapexec,
bool needmapexec, bool needmorphing) { bool needmorphing) {
int i; int i;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
switch (p[i]) { switch (p[i]) {
@ -1037,39 +1038,42 @@ static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len,
return true; return true;
} }
static const uint16_t *FindPledge(const struct Pledges *p, const char *name, static int FindPromise(const struct Pledges *p, const char *name, size_t *len) {
size_t *len) {
int i; int i;
for (i = 0; p[i].name; ++i) { for (i = 0; p[i].name; ++i) {
if (!strcasecmp(name, p[i].name)) { if (!strcasecmp(name, p[i].name)) {
*len = p[i].len; *len = p[i].len;
return p[i].syscalls; return i;
} }
} }
return 0; return -1;
} }
static int sys_pledge_linux(const char *promises, const char *execpromises) { static int sys_pledge_linux(const char *promises, const char *execpromises) {
bool ok; bool ok;
int rc = -1; int rc = -1;
size_t plen; size_t plen;
int promise;
bool needmapexec; bool needmapexec;
bool needexecnative; bool needexecnative;
bool needmorphing; bool needmorphing;
struct Filter f = {0}; struct Filter f = {0};
const uint16_t *pledge; const uint16_t *pledge;
unsigned long ipromises = -1;
char *s, *tok, *state, *start; char *s, *tok, *state, *start;
if (execpromises) return einval(); if (execpromises) return einval();
needmapexec = strstr(promises, "exec"); needmapexec = strstr(promises, "exec");
needmorphing = strstr(promises, "thread"); needmorphing = strstr(promises, "thread");
needexecnative = strstr(promises, "execnative"); needexecnative = strstr(promises, "execnative");
if ((start = s = strdup(promises)) && if ((start = s = strdup(promises)) && AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
AppendFilter(&f, kFilterStart, ARRAYLEN(kFilterStart)) &&
(needmapexec || needexecnative || AppendOriginVerification(&f)) && (needmapexec || needexecnative || AppendOriginVerification(&f)) &&
AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault), AppendPledge(&f, kPledgeLinuxDefault, ARRAYLEN(kPledgeLinuxDefault), needmapexec,
needmapexec, needmorphing)) { needmorphing)) {
for (ok = true; (tok = strtok_r(start, " \t\r\n", &state)); start = 0) { for (ok = true; (tok = strtok_r(start, " \t\r\n", &state)); start = 0) {
if (!(pledge = FindPledge(kPledgeLinux, tok, &plen))) { if ((promise = FindPromise(kPledgeLinux, tok, &plen)) != -1) {
pledge = kPledgeLinux[promise].syscalls;
ipromises &= ~(1ULL << promise);
} else {
ok = false; ok = false;
rc = einval(); rc = einval();
break; break;
@ -1084,12 +1088,29 @@ static int sys_pledge_linux(const char *promises, const char *execpromises) {
struct sock_fprog sandbox = {.len = f.n, .filter = f.p}; struct sock_fprog sandbox = {.len = f.n, .filter = f.p};
rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sandbox); rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sandbox);
} }
if (!rc) {
__promises = ipromises;
}
} }
free(f.p); free(f.p);
free(s); free(s);
return rc; return rc;
} }
static void SetPromises(const char *promises) {
int promise;
size_t plen;
char *tok, *state, *start;
unsigned long ipromises = -1;
while ((tok = strtok_r(start, " \t\r\n", &state))) {
if ((promise = FindPromise(kPledgeLinux, tok, &plen)) != -1) {
ipromises &= ~(1ULL << promise);
}
start = 0;
}
__promises = ipromises;
}
/** /**
* Restricts system operations, e.g. * Restricts system operations, e.g.
* *
@ -1216,6 +1237,9 @@ int pledge(const char *promises, const char *execpromises) {
rc = sys_pledge_linux(promises, execpromises); rc = sys_pledge_linux(promises, execpromises);
} else { } else {
rc = sys_pledge(promises, execpromises); rc = sys_pledge(promises, execpromises);
if (!rc) {
SetPromises(promises);
}
} }
STRACE("pledge(%#s, %#s) → %d% m", promises, execpromises, rc); STRACE("pledge(%#s, %#s) → %d% m", promises, execpromises, rc);
return rc; return rc;

View file

@ -21,6 +21,7 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -74,11 +75,8 @@ static textexit void LogStackUse(void) {
} }
static textstartup void LogStackUseInit(void) { static textstartup void LogStackUseInit(void) {
if (IsOpenbsd()) {
// avoid pledge() dependency on wpath
return;
}
if (IsTiny()) return; if (IsTiny()) return;
if (!PLEDGED(WPATH)) return;
if (isdirectory("o/" MODE) && if (isdirectory("o/" MODE) &&
getcwd(stacklog, sizeof(stacklog) - strlen("/o/" MODE "/stack.log"))) { getcwd(stacklog, sizeof(stacklog) - strlen("/o/" MODE "/stack.log"))) {
strcat(stacklog, "/o/" MODE "/stack.log"); strcat(stacklog, "/o/" MODE "/stack.log");

View file

@ -27,7 +27,7 @@ struct FtraceTls { /* 16 */
struct cthread_descriptor_t { struct cthread_descriptor_t {
struct cthread_descriptor_t *self; /* 0x00 */ struct cthread_descriptor_t *self; /* 0x00 */
struct FtraceTls ftrace; /* 0x08 */ struct FtraceTls ftrace; /* 0x08 */
int64_t __pad0; /* 0x10 */ void *garbages; /* 0x10 */
int64_t __pad1; /* 0x20 */ int64_t __pad1; /* 0x20 */
int64_t __pad2; /* 0x28 */ int64_t __pad2; /* 0x28 */
struct cthread_descriptor_t *self2; /* 0x30 */ struct cthread_descriptor_t *self2; /* 0x30 */

View file

@ -117,6 +117,15 @@ TEST(open, testOpenExistingForAppendWriteOnly_seeksToEnd) {
EXPECT_SYS(0, 0, close(3)); EXPECT_SYS(0, 0, close(3));
} }
TEST(open, testRelativePath_opensRelativeToDirFd) {
ASSERT_SYS(0, 0, mkdir("foo", 0755));
ASSERT_SYS(0, 3, open("foo", O_RDONLY | O_DIRECTORY));
EXPECT_SYS(0, 4, openat(3, "bar", O_WRONLY | O_TRUNC | O_CREAT, 0755));
EXPECT_TRUE(fileexists("foo/bar"));
EXPECT_SYS(0, 0, close(4));
EXPECT_SYS(0, 0, close(3));
}
int CountFds(void) { int CountFds(void) {
int i, count; int i, count;
for (count = i = 0; i < g_fds.n; ++i) { for (count = i = 0; i < g_fds.n; ++i) {

View file

@ -34,9 +34,6 @@ TEST(vfork, test) {
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET)); ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
if (!vfork()) { if (!vfork()) {
EXPECT_EQ(5, pread(fd, buf, 5, 0)); EXPECT_EQ(5, pread(fd, buf, 5, 0));
/*
* TODO(jart): DOES PREAD IN CHILD REALLY CHANGE PARENT HANDLE POSITION?
*/
ASSERT_NE(-1, lseek(fd, 0, SEEK_SET)); ASSERT_NE(-1, lseek(fd, 0, SEEK_SET));
EXPECT_STREQ("hello", buf); EXPECT_STREQ("hello", buf);
EXPECT_NE(-1, close(fd)); EXPECT_NE(-1, close(fd));

View file

@ -2585,8 +2585,8 @@ static const luaL_Reg kLuaUnix[] = {
{"rmrf", LuaUnixRmrf}, // remove file recursively {"rmrf", LuaUnixRmrf}, // remove file recursively
{"send", LuaUnixSend}, // send tcp to some address {"send", LuaUnixSend}, // send tcp to some address
{"sendto", LuaUnixSendto}, // send udp to some address {"sendto", LuaUnixSendto}, // send udp to some address
{"setfsgid", LuaUnixSetfsgid}, // set/get group id for file system ops {"setfsgid", LuaUnixSetfsgid}, // set/get group id for fs ops
{"setfsuid", LuaUnixSetfsuid}, // set/get user id for file system ops {"setfsuid", LuaUnixSetfsuid}, // set/get user id for fs ops
{"setgid", LuaUnixSetgid}, // set real group id of process {"setgid", LuaUnixSetgid}, // set real group id of process
{"setitimer", LuaUnixSetitimer}, // set alarm clock {"setitimer", LuaUnixSetitimer}, // set alarm clock
{"setpgid", LuaUnixSetpgid}, // set process group id for pid {"setpgid", LuaUnixSetpgid}, // set process group id for pid