mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-30 16:28:30 +00:00
Prevent Make from talking to public Internet
This change introduces the nointernet() function which may be called to prevent a process and its descendants from communicating with publicly routable Internet addresses. GNU Make has been modified to always call this function. In the future Landlock Make will have a way to whitelist subnets to override this behavior, or disable it entirely. Support is available for Linux only. Our firewall does not require root access. Calling nointernet() will return control to the caller inside a new process that has a SECCOMP BPF filter installed, which traps network related system calls. Your original process then becomes a permanent ptrace() supervisor that monitors all processes and threads descending from the returned child. Whenever a networking system call happens the kernel will stop the process and wakes up the monitor, which then peeks into the child memory to read the sockaddr_in to determine if it's ok. The downside to doing this is that there can be only one supervisor at a time using ptrace() on a process. So this firewall won't be enabled if you run make under strace or inside gdb. It also makes testing tricky.
This commit is contained in:
parent
8a0a2c0c36
commit
7cf66bc161
48 changed files with 4924 additions and 2046 deletions
|
@ -35,10 +35,11 @@
|
|||
#define WIFCONTINUED(s) ((s) == 0xffff)
|
||||
#define WIFEXITED(s) (!WTERMSIG(s))
|
||||
#define WIFSIGNALED(s) ((0xffff & (s)) - 1u < 0xffu)
|
||||
#define WIFSTOPPED(s) ((short)(((0xffff & (s)) * 0x10001) >> 8) > 0x7f00)
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
#define WTERMSIG(s) (127 & (s))
|
||||
#define W_STOPCODE(s) ((s) << 8 | 0177)
|
||||
#define WIFSTOPPED(s) \
|
||||
((short)(((0xffff & (unsigned)(s)) * 0x10001) >> 8) > 0x7f00)
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
#define WTERMSIG(s) (127 & (s))
|
||||
#define W_STOPCODE(s) ((s) << 8 | 0177)
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -115,6 +116,7 @@ int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
|||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
int getuid(void) libcesque;
|
||||
int iopl(int);
|
||||
int ioprio_get(int, int);
|
||||
int ioprio_set(int, int, int);
|
||||
int issetugid(void);
|
||||
|
@ -178,6 +180,7 @@ int siginterrupt(int, int);
|
|||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
int sys_ptrace(int, ...);
|
||||
int sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int tgkill(int, int, int);
|
||||
int tkill(int, int);
|
||||
|
@ -194,7 +197,6 @@ int wait(int *);
|
|||
int waitpid(int, int *, int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, ...);
|
||||
size_t GetFileSize(const char *);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/pledge.internal.h"
|
||||
#include "libc/calls/struct/bpf.h"
|
||||
|
@ -25,6 +24,7 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
@ -517,6 +517,7 @@ static const uint16_t kPledgeStdio[] = {
|
|||
__NR_linux_migrate_pages, //
|
||||
__NR_linux_sync_file_range, //
|
||||
__NR_linux_set_tid_address, //
|
||||
__NR_linux_membarrier, //
|
||||
__NR_linux_nanosleep, //
|
||||
__NR_linux_pipe, //
|
||||
__NR_linux_pipe2, //
|
||||
|
|
|
@ -19,47 +19,15 @@
|
|||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/sysv/consts/ptrace.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static const char *__ptrace_describe_request(int x) {
|
||||
if (x == -1) return "-1";
|
||||
if (x == PTRACE_TRACEME) return "PTRACE_TRACEME";
|
||||
if (x == PTRACE_PEEKDATA) return "PTRACE_PEEKDATA";
|
||||
if (x == PTRACE_GETFPREGS) return "PTRACE_GETFPREGS";
|
||||
if (x == PTRACE_PEEKTEXT) return "PTRACE_PEEKTEXT";
|
||||
if (x == PTRACE_POKEDATA) return "PTRACE_POKEDATA";
|
||||
if (x == PTRACE_PEEKUSER) return "PTRACE_PEEKUSER";
|
||||
if (x == PTRACE_POKETEXT) return "PTRACE_POKETEXT";
|
||||
if (x == PTRACE_POKEUSER) return "PTRACE_POKEUSER";
|
||||
if (x == PTRACE_GETREGS) return "PTRACE_GETREGS";
|
||||
if (x == PTRACE_GETREGSET) return "PTRACE_GETREGSET";
|
||||
if (x == PTRACE_SETFPREGS) return "PTRACE_SETFPREGS";
|
||||
if (x == PTRACE_SETREGS) return "PTRACE_SETREGS";
|
||||
if (x == PTRACE_SETREGSET) return "PTRACE_SETREGSET";
|
||||
if (x == PTRACE_GETSIGINFO) return "PTRACE_GETSIGINFO";
|
||||
if (x == PTRACE_SETSIGINFO) return "PTRACE_SETSIGINFO";
|
||||
if (x == PTRACE_PEEKSIGINFO) return "PTRACE_PEEKSIGINFO";
|
||||
if (x == PTRACE_GETSIGMASK) return "PTRACE_GETSIGMASK";
|
||||
if (x == PTRACE_SETSIGMASK) return "PTRACE_SETSIGMASK";
|
||||
if (x == PTRACE_SETOPTIONS) return "PTRACE_SETOPTIONS";
|
||||
if (x == PTRACE_GETEVENTMSG) return "PTRACE_GETEVENTMSG";
|
||||
if (x == PTRACE_CONT) return "PTRACE_CONT";
|
||||
if (x == PTRACE_SINGLESTEP) return "PTRACE_SINGLESTEP";
|
||||
if (x == PTRACE_SYSCALL) return "PTRACE_SYSCALL";
|
||||
if (x == PTRACE_LISTEN) return "PTRACE_LISTEN";
|
||||
if (x == PTRACE_KILL) return "PTRACE_KILL";
|
||||
if (x == PTRACE_INTERRUPT) return "PTRACE_INTERRUPT";
|
||||
if (x == PTRACE_ATTACH) return "PTRACE_ATTACH";
|
||||
if (x == PTRACE_SEIZE) return "PTRACE_SEIZE";
|
||||
if (x == PTRACE_SECCOMP_GET_FILTER) return "PTRACE_SECCOMP_GET_FILTER";
|
||||
if (x == PTRACE_DETACH) return "PTRACE_DETACH";
|
||||
return "PTRACE_WUT";
|
||||
}
|
||||
|
||||
/**
|
||||
* Traces process.
|
||||
*
|
||||
* This API is terrible. Consider using sys_ptrace().
|
||||
*
|
||||
* @param request can be PTRACE_xxx
|
||||
* @note de facto linux only atm
|
||||
* @vforksafe
|
||||
|
@ -69,22 +37,21 @@ long ptrace(int request, ...) {
|
|||
int pid;
|
||||
va_list va;
|
||||
bool ispeek;
|
||||
long rc, peek;
|
||||
void *addr, *data;
|
||||
long rc, peek, addr, *data;
|
||||
va_start(va, request);
|
||||
pid = va_arg(va, int);
|
||||
addr = va_arg(va, void *);
|
||||
data = va_arg(va, void *);
|
||||
addr = va_arg(va, long);
|
||||
data = va_arg(va, long *);
|
||||
va_end(va);
|
||||
if (request == -1) {
|
||||
rc = einval(); /* see consts.sh */
|
||||
} else {
|
||||
ispeek = IsLinux() && request - 1u < 3;
|
||||
if (ispeek) data = &peek;
|
||||
rc = sys_ptrace(request, pid, addr, data);
|
||||
rc = __sys_ptrace(request, pid, addr, data);
|
||||
if (rc != -1 && ispeek) rc = peek;
|
||||
}
|
||||
STRACE("ptrace(%s, %d, %p, %p) → %ld% m", __ptrace_describe_request(request),
|
||||
pid, addr, data);
|
||||
STRACE("ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(request), pid, addr,
|
||||
data, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,35 +16,45 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "net/http/ip.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
|
||||
#define IsPeek(request) (IsLinux() && (request)-1u < 3)
|
||||
|
||||
/**
|
||||
* Checks outbound address against firewall.
|
||||
* Traces process.
|
||||
*
|
||||
* The goal is to keep local software local, by raising an error if our
|
||||
* Makefile tries to talk to the Internet.
|
||||
* @param op can be PTRACE_xxx
|
||||
* @param pid is child process id
|
||||
* @param addr points inside child address space
|
||||
* @param data is address of output word when peeking
|
||||
* @note de facto linux only
|
||||
* @vforksafe
|
||||
*/
|
||||
void _firewall(const void *addr, uint32_t addrsize) {
|
||||
char b[64], *p;
|
||||
if (!IsTiny() && addr && addrsize >= sizeof(struct sockaddr_in) &&
|
||||
((struct sockaddr_in *)addr)->sin_family == AF_INET &&
|
||||
IsPublicIp(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)) &&
|
||||
IsRunningUnderMake()) {
|
||||
p = stpcpy(b, "make shan't internet: ");
|
||||
p = stpcpy(p, inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
|
||||
*p++ = '\n';
|
||||
write(2, b, p - b);
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
__restorewintty();
|
||||
_Exit(66);
|
||||
int sys_ptrace(int op, ...) {
|
||||
va_list va;
|
||||
int rc, pid;
|
||||
long addr, *data;
|
||||
va_start(va, op);
|
||||
pid = va_arg(va, int);
|
||||
addr = va_arg(va, long);
|
||||
data = va_arg(va, long *);
|
||||
va_end(va);
|
||||
rc = __sys_ptrace(op, pid, addr, data);
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
if (rc != -1 && IsPeek(op) && data) {
|
||||
STRACE("sys_ptrace(%s, %d, %p, [%p]) → %p% m", DescribePtrace(op), pid,
|
||||
addr, *data, rc);
|
||||
} else {
|
||||
STRACE("sys_ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(op), pid,
|
||||
addr, data, rc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
|
@ -104,10 +104,10 @@ i32 sys_uname(void *) hidden;
|
|||
i32 sys_unlinkat(i32, const char *, i32) hidden;
|
||||
i32 sys_unmount(const char *, i32) hidden;
|
||||
i32 sys_unveil(const char *, const char *) hidden;
|
||||
i64 __sys_ptrace(i32, i32, i64, long *) hidden;
|
||||
i64 sys_copy_file_range(i32, long *, i32, long *, u64, u32) hidden;
|
||||
i64 sys_getrandom(void *, u64, u32) hidden;
|
||||
i64 sys_pread(i32, void *, u64, i64, i64) hidden;
|
||||
i64 sys_ptrace(int, i32, void *, void *) hidden;
|
||||
i64 sys_pwrite(i32, const void *, u64, i64, i64) hidden;
|
||||
i64 sys_read(i32, void *, u64) hidden;
|
||||
i64 sys_readlink(const char *, char *, u64) hidden;
|
||||
|
|
|
@ -13,11 +13,6 @@
|
|||
#define DEV_BSIZE 512
|
||||
#define NOGROUP (-1)
|
||||
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -32,9 +33,12 @@
|
|||
* @error ENOENT
|
||||
*/
|
||||
int truncate(const char *path, uint64_t length) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
return sys_truncate(path, length, length);
|
||||
rc = sys_truncate(path, length, length);
|
||||
} else {
|
||||
return sys_truncate_nt(path, length);
|
||||
rc = sys_truncate_nt(path, length);
|
||||
}
|
||||
STRACE("truncate(%#s, %'ld) → %d% m", path, length, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,18 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dns/consts.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/dns/dnsheader.h"
|
||||
#include "libc/dns/dnsquestion.h"
|
||||
#include "libc/dns/resolvconf.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
@ -101,7 +101,6 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
|
|||
a4 = (struct sockaddr_in *)addr;
|
||||
a4->sin_family = AF_INET;
|
||||
memcpy(&a4->sin_addr.s_addr, p + 10, 4);
|
||||
_firewall(a4, sizeof(struct sockaddr_in));
|
||||
break;
|
||||
}
|
||||
p += 10 + rdlength;
|
||||
|
|
|
@ -53,6 +53,8 @@ const char *DescribePersonalityFlags(char[128], int);
|
|||
const char *DescribePollFlags(char[64], int);
|
||||
const char *DescribePrctlOperation(int);
|
||||
const char *DescribeProtFlags(char[48], int);
|
||||
const char *DescribePtrace(char[12], int);
|
||||
const char *DescribePtraceEvent(char[32], int);
|
||||
const char *DescribeRemapFlags(char[48], int);
|
||||
const char *DescribeRlimit(char[64], int, const struct rlimit *);
|
||||
const char *DescribeRlimitName(char[20], int);
|
||||
|
@ -101,6 +103,8 @@ void DescribeIovNt(const struct NtIovec *, uint32_t, ssize_t);
|
|||
#define DescribePersonalityFlags(p) DescribePersonalityFlags(alloca(128), p)
|
||||
#define DescribePollFlags(p) DescribePollFlags(alloca(64), p)
|
||||
#define DescribeProtFlags(dirfd) DescribeProtFlags(alloca(48), dirfd)
|
||||
#define DescribePtrace(i) DescribePtrace(alloca(12), i)
|
||||
#define DescribePtraceEvent(x) DescribePtraceEvent(alloca(32), x)
|
||||
#define DescribeRemapFlags(dirfd) DescribeRemapFlags(alloca(48), dirfd)
|
||||
#define DescribeRlimit(rc, rl) DescribeRlimit(alloca(64), rc, rl)
|
||||
#define DescribeRlimitName(rl) DescribeRlimitName(alloca(20), rl)
|
||||
|
|
57
libc/intrin/describeptrace.c
Normal file
57
libc/intrin/describeptrace.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*-*- 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/fmt/itoa.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/sysv/consts/ptrace.h"
|
||||
|
||||
const char *(DescribePtrace)(char buf[12], int x) {
|
||||
if (x == -1) return "-1";
|
||||
if (x == PTRACE_TRACEME) return "PTRACE_TRACEME";
|
||||
if (x == PTRACE_PEEKDATA) return "PTRACE_PEEKDATA";
|
||||
if (x == PTRACE_GETFPREGS) return "PTRACE_GETFPREGS";
|
||||
if (x == PTRACE_PEEKTEXT) return "PTRACE_PEEKTEXT";
|
||||
if (x == PTRACE_POKEDATA) return "PTRACE_POKEDATA";
|
||||
if (x == PTRACE_PEEKUSER) return "PTRACE_PEEKUSER";
|
||||
if (x == PTRACE_POKETEXT) return "PTRACE_POKETEXT";
|
||||
if (x == PTRACE_POKEUSER) return "PTRACE_POKEUSER";
|
||||
if (x == PTRACE_GETREGS) return "PTRACE_GETREGS";
|
||||
if (x == PTRACE_GETREGSET) return "PTRACE_GETREGSET";
|
||||
if (x == PTRACE_SETFPREGS) return "PTRACE_SETFPREGS";
|
||||
if (x == PTRACE_SETREGS) return "PTRACE_SETREGS";
|
||||
if (x == PTRACE_SETREGSET) return "PTRACE_SETREGSET";
|
||||
if (x == PTRACE_GETSIGINFO) return "PTRACE_GETSIGINFO";
|
||||
if (x == PTRACE_SETSIGINFO) return "PTRACE_SETSIGINFO";
|
||||
if (x == PTRACE_PEEKSIGINFO) return "PTRACE_PEEKSIGINFO";
|
||||
if (x == PTRACE_GETSIGMASK) return "PTRACE_GETSIGMASK";
|
||||
if (x == PTRACE_SETSIGMASK) return "PTRACE_SETSIGMASK";
|
||||
if (x == PTRACE_SETOPTIONS) return "PTRACE_SETOPTIONS";
|
||||
if (x == PTRACE_GETEVENTMSG) return "PTRACE_GETEVENTMSG";
|
||||
if (x == PTRACE_CONT) return "PTRACE_CONT";
|
||||
if (x == PTRACE_SINGLESTEP) return "PTRACE_SINGLESTEP";
|
||||
if (x == PTRACE_SYSCALL) return "PTRACE_SYSCALL";
|
||||
if (x == PTRACE_LISTEN) return "PTRACE_LISTEN";
|
||||
if (x == PTRACE_KILL) return "PTRACE_KILL";
|
||||
if (x == PTRACE_INTERRUPT) return "PTRACE_INTERRUPT";
|
||||
if (x == PTRACE_ATTACH) return "PTRACE_ATTACH";
|
||||
if (x == PTRACE_SEIZE) return "PTRACE_SEIZE";
|
||||
if (x == PTRACE_SECCOMP_GET_FILTER) return "PTRACE_SECCOMP_GET_FILTER";
|
||||
if (x == PTRACE_DETACH) return "PTRACE_DETACH";
|
||||
FormatInt32(buf, x);
|
||||
return buf;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,21 +16,19 @@
|
|||
│ 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/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/sysv/consts/ptrace.h"
|
||||
|
||||
/**
|
||||
* Returns the byte length of file by path.
|
||||
*
|
||||
* @return number of bytes, or -1ul w/ errno
|
||||
* @see getfiledescriptorsize()
|
||||
*/
|
||||
size_t GetFileSize(const char *pathname) {
|
||||
struct stat st;
|
||||
if (stat(pathname, &st) == -1) return SIZE_MAX;
|
||||
return st.st_size;
|
||||
const char *(DescribePtraceEvent)(char buf[32], int x) {
|
||||
if (x == PTRACE_EVENT_FORK) return "PTRACE_EVENT_FORK";
|
||||
if (x == PTRACE_EVENT_VFORK) return "PTRACE_EVENT_VFORK";
|
||||
if (x == PTRACE_EVENT_CLONE) return "PTRACE_EVENT_CLONE";
|
||||
if (x == PTRACE_EVENT_EXEC) return "PTRACE_EVENT_EXEC";
|
||||
if (x == PTRACE_EVENT_VFORK_DONE) return "PTRACE_EVENT_VFORK_DONE";
|
||||
if (x == PTRACE_EVENT_EXIT) return "PTRACE_EVENT_EXIT";
|
||||
if (x == PTRACE_EVENT_SECCOMP) return "PTRACE_EVENT_SECCOMP";
|
||||
if (x == PTRACE_EVENT_STOP) return "PTRACE_EVENT_STOP";
|
||||
FormatInt32(buf, x);
|
||||
return buf;
|
||||
}
|
|
@ -40,7 +40,6 @@
|
|||
int connect(int fd, const void *addr, uint32_t addrsize) {
|
||||
int rc;
|
||||
if (addr && !(IsAsan() && !__asan_is_valid(addr, addrsize))) {
|
||||
_firewall(addr, addrsize);
|
||||
if (!IsWindows()) {
|
||||
rc = sys_connect(fd, addr, addrsize);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
|
|
|
@ -91,8 +91,6 @@ struct SockFd {
|
|||
|
||||
errno_t __dos2errno(uint32_t) hidden;
|
||||
|
||||
void _firewall(const void *, uint32_t) hidden;
|
||||
|
||||
int32_t __sys_accept(int32_t, void *, uint32_t *, int) dontdiscard hidden;
|
||||
int32_t __sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden;
|
||||
int32_t __sys_bind(int32_t, const void *, uint32_t) hidden;
|
||||
|
|
348
libc/sock/nointernet.c
Normal file
348
libc/sock/nointernet.c
Normal file
|
@ -0,0 +1,348 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/bpf.h"
|
||||
#include "libc/calls/struct/filter.h"
|
||||
#include "libc/calls/struct/seccomp.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/msghdr.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/audit.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/nrlinux.h"
|
||||
#include "libc/sysv/consts/pr.h"
|
||||
#include "libc/sysv/consts/ptrace.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/ip.h"
|
||||
|
||||
#define ORIG_RAX 120
|
||||
#define RAX 80
|
||||
#define RDI 112
|
||||
#define RSI 104
|
||||
#define RDX 96
|
||||
#define R8 72
|
||||
#define R9 64
|
||||
#define __WALL 0x40000000
|
||||
|
||||
#define OFF(f) offsetof(struct seccomp_data, f)
|
||||
|
||||
#if 0
|
||||
#define DEBUG(...) kprintf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG(...) donothing
|
||||
#endif
|
||||
|
||||
#define ORDIE(x) \
|
||||
do { \
|
||||
if (UNLIKELY((x) == -1)) { \
|
||||
DEBUG("%s:%d: %s failed %m\n", __FILE__, __LINE__, #x); \
|
||||
asm("hlt"); \
|
||||
unreachable; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static const struct sock_filter kInetBpf[] = {
|
||||
// cargo culted architecture assertion
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(arch)),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0),
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
|
||||
// block system calls from the future
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, OFF(nr)),
|
||||
BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, __NR_linux_memfd_secret, 0, 1),
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | 38), // ENOSYS
|
||||
// only allow local and internet sockets
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_socket, 0, 5),
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x001, 2, 0), // AF_UNIX
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x002, 1, 0), // AF_INET
|
||||
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | 1), // EPERM
|
||||
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)),
|
||||
// support for these not implemented yet
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x133, 0, 1), // sendmmsg
|
||||
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | 1), // EPERM
|
||||
// trace syscalls with struct sockaddr
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x02e, 3, 0), // sendmsg
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x02c, 2, 0), // sendto
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x031, 1, 0), // bind
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x02a, 0, 1), // connect
|
||||
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
|
||||
// default course of action
|
||||
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
|
||||
};
|
||||
|
||||
static int PeekData(int pid, long addr, void *buf, size_t size) {
|
||||
long i, j, w;
|
||||
for (i = 0; i < size; i += sizeof(long)) {
|
||||
if (sys_ptrace(PTRACE_PEEKTEXT, pid, addr + i, &w) != -1) {
|
||||
for (j = 0; i + j < size && j < sizeof(long); ++j) {
|
||||
((char *)buf)[i + j] = w;
|
||||
w >>= 8;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void LogProcessEvent(int main, int pid, int ws) {
|
||||
DEBUG("trace: %s%06d%s 0x%06x", //
|
||||
pid == main ? "\e[31;1m" : "", //
|
||||
pid, //
|
||||
pid == main ? "\e[0m" : "", //
|
||||
ws);
|
||||
if (WIFEXITED(ws)) {
|
||||
DEBUG(" exit %d", WEXITSTATUS(ws));
|
||||
}
|
||||
if (WIFSIGNALED(ws)) {
|
||||
DEBUG(" sig %d", WTERMSIG(ws));
|
||||
}
|
||||
if (WIFSTOPPED(ws)) {
|
||||
DEBUG(" stop %s %s", strsignal(WSTOPSIG(ws)),
|
||||
DescribePtraceEvent((ws & 0xff0000) >> 16));
|
||||
}
|
||||
if (WIFCONTINUED(ws)) {
|
||||
DEBUG(" cont");
|
||||
}
|
||||
if (WCOREDUMP(ws)) {
|
||||
DEBUG(" core");
|
||||
}
|
||||
DEBUG("\n");
|
||||
}
|
||||
|
||||
static int Raise(int sig) {
|
||||
sigset_t mask;
|
||||
sigaction(sig, &(struct sigaction){0}, 0);
|
||||
sigfillset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, 0);
|
||||
kill(getpid(), sig);
|
||||
sigdelset(&mask, sig);
|
||||
sigprocmask(SIG_SETMASK, &mask, 0);
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
|
||||
static bool IsSockaddrAllowed(struct sockaddr_storage *addr) {
|
||||
uint32_t ip;
|
||||
if (addr->ss_family == AF_UNIX) {
|
||||
return true;
|
||||
}
|
||||
if (addr->ss_family == AF_INET) {
|
||||
ip = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||
if (!IsPublicIp(ip)) {
|
||||
return true;
|
||||
} else {
|
||||
kprintf("warning: attempted to communicate with public ip "
|
||||
"%hhd.%hhd.%hhd.%hhd\n",
|
||||
ip >> 24, ip >> 16, ip >> 8, ip);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG("bad family %d\n", addr->ss_family);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void OnSockaddrSyscall(int pid, int r1, int r2) {
|
||||
long si, dx;
|
||||
uint32_t addrlen;
|
||||
struct sockaddr_storage addr = {0};
|
||||
ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, r1, &si));
|
||||
ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, r2, &dx));
|
||||
addrlen = dx;
|
||||
if (!si) {
|
||||
// if address isn't supplied, it's probably safe. for example,
|
||||
// send() is implemented in cosmo using sendto() with 0/0 addr
|
||||
return;
|
||||
}
|
||||
if (PeekData(pid, si, &addr, MIN(addrlen, sizeof(addr))) == -1) {
|
||||
DEBUG("failed to peek addr\n"); // probably an efault
|
||||
goto Deny;
|
||||
}
|
||||
if (IsSockaddrAllowed(&addr)) {
|
||||
return;
|
||||
} else {
|
||||
goto Deny;
|
||||
}
|
||||
Deny:
|
||||
ORDIE(sys_ptrace(PTRACE_POKEUSER, pid, ORIG_RAX, -1));
|
||||
}
|
||||
|
||||
static void OnSendmsg(int pid) {
|
||||
long si;
|
||||
struct msghdr msg = {0};
|
||||
struct sockaddr_storage addr = {0};
|
||||
ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, RSI, &si));
|
||||
if (PeekData(pid, si, &msg, sizeof(msg)) == -1) {
|
||||
DEBUG("failed to peek msg\n"); // probably an efault
|
||||
goto Deny;
|
||||
}
|
||||
if (!msg.msg_name) {
|
||||
// if address isn't supplied, it's probably fine.
|
||||
return;
|
||||
}
|
||||
if (PeekData(pid, (long)msg.msg_name, &addr,
|
||||
MIN(msg.msg_namelen, sizeof(addr))) == -1) {
|
||||
DEBUG("failed to peek msg name\n"); // probably an efault
|
||||
goto Deny;
|
||||
}
|
||||
if (IsSockaddrAllowed(&addr)) {
|
||||
return;
|
||||
} else {
|
||||
goto Deny;
|
||||
}
|
||||
Deny:
|
||||
ORDIE(sys_ptrace(PTRACE_POKEUSER, pid, ORIG_RAX, -1));
|
||||
}
|
||||
|
||||
static void HandleSeccompTrace(int pid) {
|
||||
long ax;
|
||||
ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, ORIG_RAX, &ax));
|
||||
switch (ax) {
|
||||
case 0x031: // bind
|
||||
case 0x02a: // connect
|
||||
OnSockaddrSyscall(pid, RSI, RDX);
|
||||
break;
|
||||
case 0x02c: // sendto
|
||||
OnSockaddrSyscall(pid, R8, R9);
|
||||
break;
|
||||
case 0x02e: // sendmsg
|
||||
OnSendmsg(pid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int WaitForTrace(int main) {
|
||||
int ws, pid;
|
||||
for (;;) {
|
||||
// waits for state change on any child process or thread
|
||||
// eintr isn't possible since we're blocking all signals
|
||||
ORDIE(pid = waitpid(-1, &ws, __WALL));
|
||||
LogProcessEvent(main, pid, ws);
|
||||
// once main child exits or dies, we exit / die the same way. we're
|
||||
// not currently tracking pids, so it's important that a child does
|
||||
// not exit before its children. otherwise the grandchildren get in
|
||||
// a permanently stopped state. to address that, we'll send sigterm
|
||||
// to the process group which we defined earlier.
|
||||
if (WIFEXITED(ws)) {
|
||||
if (pid == main) {
|
||||
kill(-getpid(), SIGTERM);
|
||||
_Exit(WEXITSTATUS(ws));
|
||||
}
|
||||
} else if (WIFSIGNALED(ws)) {
|
||||
if (pid == main) {
|
||||
kill(-getpid(), SIGTERM);
|
||||
Raise(WTERMSIG(ws));
|
||||
}
|
||||
} else if (WIFSTOPPED(ws)) {
|
||||
if ((ws >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
|
||||
return pid;
|
||||
} else if ((ws >> 8) == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) {
|
||||
ORDIE(ptrace(PTRACE_CONT, pid, 0, 0));
|
||||
} else if ((ws >> 8) == (SIGTRAP | (PTRACE_EVENT_FORK << 8)) ||
|
||||
(ws >> 8) == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) ||
|
||||
(ws >> 8) == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
|
||||
ORDIE(ptrace(PTRACE_CONT, pid, 0, 0));
|
||||
} else {
|
||||
ORDIE(ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(ws)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables internet access.
|
||||
*/
|
||||
int nointernet(void) {
|
||||
int ws, act, main;
|
||||
sigset_t set, old;
|
||||
char path[PATH_MAX];
|
||||
struct sock_fprog prog = {.filter = kInetBpf, .len = ARRAYLEN(kInetBpf)};
|
||||
|
||||
// seccomp bpf and ptrace are pretty much just linux for now.
|
||||
if (!IsLinux() || !__is_linux_2_6_23()) {
|
||||
return enosys();
|
||||
}
|
||||
|
||||
// ensure we're at the root of a process group, so we're able to
|
||||
// broadcast a termination signal later on that catches dangling
|
||||
// subprocesss our child forgot to destroy. without calling this
|
||||
// subprocesses could end up permanently stopped if monitor dies
|
||||
setpgrp();
|
||||
|
||||
// prevent crash handlers from intercepting sigsegv
|
||||
ORDIE(sigfillset(&set));
|
||||
ORDIE(sigprocmask(SIG_SETMASK, &set, &old));
|
||||
|
||||
// create traced child that'll replace this program
|
||||
if ((main = fork()) == -1) {
|
||||
ORDIE(sigprocmask(SIG_SETMASK, &old, 0));
|
||||
return -1;
|
||||
}
|
||||
if (!main) {
|
||||
if (sys_ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
|
||||
// there can be only one
|
||||
// throw sigsegv on eperm
|
||||
// we're already being traced
|
||||
asm("hlt");
|
||||
}
|
||||
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
ORDIE(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog));
|
||||
ORDIE(kill(getpid(), SIGSTOP));
|
||||
ORDIE(sigprocmask(SIG_SETMASK, &old, 0));
|
||||
// return to caller from child
|
||||
return 0;
|
||||
}
|
||||
|
||||
// wait for child to stop itself
|
||||
ORDIE(waitpid(main, &ws, 0));
|
||||
if (WIFSIGNALED(ws)) {
|
||||
// child couldn't enable ptrace or seccomp
|
||||
sigprocmask(SIG_SETMASK, &old, 0);
|
||||
return eperm();
|
||||
}
|
||||
assert(WIFSTOPPED(ws));
|
||||
|
||||
// parent process becomes monitor of subprocess tree. all signals
|
||||
// continue to be blocked since we assume they'll also be sent to
|
||||
// children, which will die, and then the monitor dies afterwards
|
||||
ORDIE(sys_ptrace(PTRACE_SETOPTIONS, main, 0,
|
||||
PTRACE_O_TRACESECCOMP | PTRACE_O_TRACEFORK |
|
||||
PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE |
|
||||
PTRACE_O_TRACEEXEC));
|
||||
for (act = main;;) {
|
||||
ORDIE(sys_ptrace(PTRACE_CONT, act, 0, 0));
|
||||
act = WaitForTrace(main);
|
||||
HandleSeccompTrace(act);
|
||||
}
|
||||
}
|
|
@ -58,7 +58,6 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
|
|||
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
_firewall(opt_addr, addrsize);
|
||||
if (!IsWindows()) {
|
||||
if (!IsBsd() || !opt_addr) {
|
||||
rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize);
|
||||
|
|
|
@ -24,6 +24,7 @@ uint32_t inet_addr(const char *);
|
|||
int parseport(const char *);
|
||||
uint32_t *GetHostIps(void);
|
||||
|
||||
int nointernet(void);
|
||||
int socket(int, int, int);
|
||||
int accept(int, void *, uint32_t *);
|
||||
int accept4(int, void *, uint32_t *, int);
|
||||
|
|
2
libc/sysv/calls/__sys_ptrace.s
Normal file
2
libc/sysv/calls/__sys_ptrace.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_ptrace,0x01a01a01a201a065,globl,hidden
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_ptrace,0x01a01a01a201a065,globl,hidden
|
|
@ -139,7 +139,7 @@ scall sys_getrlimit 0x0c20c20c220c2061 globl hidden
|
|||
scall __sys_getrusage 0x1bd0130752075062 globl hidden
|
||||
scall sys_sysinfo 0xfffffffffffff063 globl hidden
|
||||
scall sys_times 0xfffffffffffff064 globl hidden
|
||||
scall sys_ptrace 0x01a01a01a201a065 globl hidden
|
||||
scall __sys_ptrace 0x01a01a01a201a065 globl hidden # ptrace() wrapper api is terrible
|
||||
scall sys_syslog 0xfffffffffffff067 globl hidden
|
||||
scall sys_getuid 0x0180180182018066 globl hidden
|
||||
scall sys_getgid 0x02f02f02f202f068 globl hidden
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue