mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-03 09:48:29 +00:00
Rewrite Linux pledge() code so it can be a payload
It's now possible to build our pledge() polyfill as a dynamic shared object that can be injected into a glibc executable using LD_PRELOAD
This commit is contained in:
parent
7bd4179b9b
commit
0277d7d6e9
37 changed files with 1980 additions and 1600 deletions
|
@ -123,6 +123,7 @@ int killpg(int, int);
|
|||
int link(const char *, const char *) dontthrow;
|
||||
int linkat(int, const char *, int, const char *, int);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
int mincore(void *, size_t, unsigned char *);
|
||||
int mkdir(const char *, uint32_t);
|
||||
int mkdirat(int, const char *, uint32_t);
|
||||
|
|
|
@ -188,11 +188,20 @@ o/$(MODE)/libc/calls/_timespec_frommicros.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
|
||||
o/$(MODE)/libc/calls/pledge.o \
|
||||
o/$(MODE)/libc/calls/pledge-linux.o \
|
||||
o/$(MODE)/libc/calls/unveil.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
# we want -Os because:
|
||||
# it makes a big difference
|
||||
# we need pic because:
|
||||
# so it can be an LD_PRELOAD payload
|
||||
o/$(MODE)/libc/calls/pledge-linux.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os \
|
||||
-fPIC
|
||||
|
||||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/pledge.h"
|
||||
#include "libc/calls/pledge.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -30,8 +32,6 @@
|
|||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_pledge_linux(unsigned long);
|
||||
|
||||
/**
|
||||
* Replaces current process with program.
|
||||
*
|
||||
|
@ -72,7 +72,7 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && weaken(sys_pledge_linux)) {
|
||||
rc = weaken(sys_pledge_linux)(__execpromises);
|
||||
rc = weaken(sys_pledge_linux)(__execpromises, __pledge_mode, false);
|
||||
}
|
||||
if (!rc) {
|
||||
rc = sys_execve(prog, argv, envp);
|
||||
|
|
|
@ -136,6 +136,6 @@ char *GetProgramExecutableName(void) {
|
|||
return program_executable_name;
|
||||
}
|
||||
|
||||
const void *const GetProgramExecutableNameCtor[] initarray = {
|
||||
GetProgramExecutableName,
|
||||
};
|
||||
/* const void *const GetProgramExecutableNameCtor[] initarray = { */
|
||||
/* GetProgramExecutableName, */
|
||||
/* }; */
|
||||
|
|
35
libc/calls/memfd_create.c
Normal file
35
libc/calls/memfd_create.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*-*- 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/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
||||
/**
|
||||
* Creates anonymous file.
|
||||
*
|
||||
* @param name is used for the `/proc/self/fd/FD` symlink
|
||||
* @param flags can have `MFD_CLOEXEC`, `MFD_ALLOW_SEALING`
|
||||
* @raise ENOSYS if not RHEL8+
|
||||
*/
|
||||
int memfd_create(const char *name, unsigned int flags) {
|
||||
int rc;
|
||||
rc = sys_memfd_create(name, flags);
|
||||
STRACE("memfd_create(%#s, %#x) → %d% m", name, flags, rc);
|
||||
return rc;
|
||||
}
|
66
libc/calls/parsepromises.c
Normal file
66
libc/calls/parsepromises.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*-*- 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/pledge.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static int FindPromise(const char *name) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(kPledge); ++i) {
|
||||
if (!strcasecmp(name, kPledge[i].name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the arguments to pledge() into a bitmask.
|
||||
*
|
||||
* @return 0 on success, or -1 if invalid
|
||||
*/
|
||||
int ParsePromises(const char *promises, unsigned long *out) {
|
||||
int rc = 0;
|
||||
int promise;
|
||||
unsigned long ipromises;
|
||||
char *tok, *state, *start, buf[256];
|
||||
if (promises) {
|
||||
ipromises = -1;
|
||||
if (memccpy(buf, promises, 0, sizeof(buf))) {
|
||||
start = buf;
|
||||
while ((tok = strtok_r(start, " \t\r\n", &state))) {
|
||||
if ((promise = FindPromise(tok)) != -1) {
|
||||
ipromises &= ~(1ULL << promise);
|
||||
} else {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
start = 0;
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
ipromises = 0;
|
||||
}
|
||||
if (!rc) {
|
||||
*out = ipromises;
|
||||
}
|
||||
return rc;
|
||||
}
|
1625
libc/calls/pledge-linux.c
Normal file
1625
libc/calls/pledge-linux.c
Normal file
File diff suppressed because it is too large
Load diff
1568
libc/calls/pledge.c
1568
libc/calls/pledge.c
File diff suppressed because it is too large
Load diff
16
libc/calls/pledge.h
Normal file
16
libc/calls/pledge.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
enum PledgeMode {
|
||||
kPledgeModeKillThread,
|
||||
kPledgeModeKillProcess,
|
||||
kPledgeModeErrno,
|
||||
};
|
||||
|
||||
extern enum PledgeMode __pledge_mode;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_PLEDGE_H_ */
|
|
@ -1,9 +1,20 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_PLEDGE_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_PLEDGE_INTERNAL_H_
|
||||
#include "libc/calls/pledge.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int ParsePromises(const char *, unsigned long *);
|
||||
struct Pledges {
|
||||
const char *name;
|
||||
const uint16_t *syscalls;
|
||||
const size_t len;
|
||||
};
|
||||
|
||||
hidden extern const struct Pledges kPledge[PROMISE_LEN_];
|
||||
|
||||
int sys_pledge_linux(unsigned long, enum PledgeMode, bool) hidden;
|
||||
int ParsePromises(const char *, unsigned long *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/getconsolectrlevent.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
|
@ -39,7 +41,7 @@ static textwindows inline bool HasWorkingConsole(void) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sends signal to this process.
|
||||
* Sends signal to this thread.
|
||||
*
|
||||
* @param sig can be SIGALRM, SIGINT, SIGTERM, SIGKILL, etc.
|
||||
* @return 0 on success or -1 w/ errno
|
||||
|
@ -56,8 +58,7 @@ int raise(int sig) {
|
|||
x = 1 / x;
|
||||
rc = 0;
|
||||
} else if (!IsWindows()) {
|
||||
// XXX: should be tkill() or tgkill() on linux
|
||||
rc = sys_kill(getpid(), sig, 1);
|
||||
rc = sys_tkill(gettid(), sig, 0);
|
||||
} else {
|
||||
if (HasWorkingConsole() && (event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||
// XXX: MSDN says "If this parameter is zero, the signal is
|
||||
|
|
|
@ -290,9 +290,9 @@ int sys_unveil_linux(const char *path, const char *permissions) {
|
|||
* possible to use opendir() and go fishing for paths which weren't
|
||||
* previously known.
|
||||
*
|
||||
* 5. Use ftruncate() rather than truncate(). One of the backdoors with
|
||||
* Landlock is it currently can't restrict truncate() and setxattr()
|
||||
* which permits certain kinds of modifications to files outside the
|
||||
* 5. Use ftruncate() rather than truncate(). One issue Landlock hasn't
|
||||
* addressed yet is restrictions over truncate() and setxattr() which
|
||||
* could permit certain kinds of modifications to files outside the
|
||||
* sandbox. When your policy is committed, we install a SECCOMP BPF
|
||||
* filter to disable those calls, however similar trickery may be
|
||||
* possible through other unaddressed calls like ioctl(). Using the
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue