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:
*
* - `SCHED_OTHER` (or `SCHED_NORMAL`) for the default policy
*
* - `SCHED_RR` for real-time round-robin scheduling
*
* - `SCHED_FIFO` for real-time first-in first-out scheduling
*
* - `SCHED_BATCH` for "batch" style execution of processes if
* 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:
*
@ -65,7 +75,9 @@
* greater than or equal to sched_get_priority_min(policy) and less
* 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`
* 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
* 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/dce.h"
#include "libc/errno.h"
#include "libc/intrin/promises.internal.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
@ -47,8 +48,7 @@ static union metatermios __oldtermios;
static textstartup void __oldtermios_init() {
int e;
e = errno;
if (!IsOpenbsd() && // avoid pledge(tty)
sys_ioctl(0, TCGETS, &__oldtermios) != -1) {
if (PLEDGED(TTY) && sys_ioctl(0, TCGETS, &__oldtermios) != -1) {
__isrestorable = true;
}
errno = e;
@ -60,7 +60,7 @@ const void *const __oldtermios_ctor[] initarray = {
void __restore_tty(void) {
int e;
if (__isrestorable && !__isworker && !__nocolor) {
if (__isrestorable && PLEDGED(TTY) && !__isworker && !__nocolor) {
e = errno;
sys_write(0, ANSI_RESTORE, __strlen(ANSI_RESTORE));
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);
__stpcpy(hostname, "unknown");
gethostname(hostname, sizeof(hostname));
kprintf("check failed on %s pid %d\n", hostname, getpid());
kprintf("\tCHECK_%^s(%s, %s);\n", suffix, wantstr, gotstr);
kprintf("\t\t → %p (%s)\n", want, wantstr);
kprintf("\t\t%s %p (%s)\n", opstr, got, gotstr);
kprintf("check failed on %s pid %d\n"
"\tCHECK_%^s(%s, %s);\n"
"\t\t → %p (%s)\n"
"\t\t%s %p (%s)\n", //
hostname, getpid(), //
suffix, wantstr, gotstr, //
want, wantstr, //
opstr, got, gotstr);
if (!isempty(fmt)) {
kprintf("\t");
va_start(va, fmt);

View file

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

View file

@ -21,6 +21,7 @@
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
@ -74,11 +75,8 @@ static textexit void LogStackUse(void) {
}
static textstartup void LogStackUseInit(void) {
if (IsOpenbsd()) {
// avoid pledge() dependency on wpath
return;
}
if (IsTiny()) return;
if (!PLEDGED(WPATH)) return;
if (isdirectory("o/" MODE) &&
getcwd(stacklog, sizeof(stacklog) - strlen("/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 *self; /* 0x00 */
struct FtraceTls ftrace; /* 0x08 */
int64_t __pad0; /* 0x10 */
void *garbages; /* 0x10 */
int64_t __pad1; /* 0x20 */
int64_t __pad2; /* 0x28 */
struct cthread_descriptor_t *self2; /* 0x30 */

View file

@ -117,6 +117,15 @@ TEST(open, testOpenExistingForAppendWriteOnly_seeksToEnd) {
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 i, count;
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));
if (!vfork()) {
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));
EXPECT_STREQ("hello", buf);
EXPECT_NE(-1, close(fd));

View file

@ -2585,20 +2585,20 @@ static const luaL_Reg kLuaUnix[] = {
{"rmrf", LuaUnixRmrf}, // remove file recursively
{"send", LuaUnixSend}, // send tcp to some address
{"sendto", LuaUnixSendto}, // send udp to some address
{"setfsgid", LuaUnixSetfsgid}, // set/get group id for file system ops
{"setfsuid", LuaUnixSetfsuid}, // set/get user id for file system ops
{"setgid", LuaUnixSetgid}, // set real group id of process
{"setitimer", LuaUnixSetitimer}, // set alarm clock
{"setpgid", LuaUnixSetpgid}, // set process group id for pid
{"setpgrp", LuaUnixSetpgrp}, // sets process group id
{"setresgid", LuaUnixSetresgid}, // sets real/effective/saved gids
{"setresuid", LuaUnixSetresuid}, // sets real/effective/saved uids
{"setrlimit", LuaUnixSetrlimit}, // prevent cpu memory bombs
{"setsid", LuaUnixSetsid}, // create a new session id
{"setsockopt", LuaUnixSetsockopt}, // tune socket options
{"setuid", LuaUnixSetuid}, // set real user id of process
{"shutdown", LuaUnixShutdown}, // make socket half empty or full
{"sigaction", LuaUnixSigaction}, // install signal handler
{"setfsgid", LuaUnixSetfsgid}, // set/get group id for fs ops
{"setfsuid", LuaUnixSetfsuid}, // set/get user id for fs ops
{"setgid", LuaUnixSetgid}, // set real group id of process
{"setitimer", LuaUnixSetitimer}, // set alarm clock
{"setpgid", LuaUnixSetpgid}, // set process group id for pid
{"setpgrp", LuaUnixSetpgrp}, // sets process group id
{"setresgid", LuaUnixSetresgid}, // sets real/effective/saved gids
{"setresuid", LuaUnixSetresuid}, // sets real/effective/saved uids
{"setrlimit", LuaUnixSetrlimit}, // prevent cpu memory bombs
{"setsid", LuaUnixSetsid}, // create a new session id
{"setsockopt", LuaUnixSetsockopt}, // tune socket options
{"setuid", LuaUnixSetuid}, // set real user id of process
{"shutdown", LuaUnixShutdown}, // make socket half empty or full
{"sigaction", LuaUnixSigaction}, // install signal handler
{"sigprocmask", LuaUnixSigprocmask}, // change signal mask
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
{"siocgifconf", LuaUnixSiocgifconf}, // get list of network interfaces