diff --git a/Makefile b/Makefile
index 37b7f5fac..9956c6589 100644
--- a/Makefile
+++ b/Makefile
@@ -60,7 +60,7 @@
# build/config.mk
SHELL = build/bootstrap/cocmd.com
-HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu
+HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
MAKEFLAGS += --no-builtin-rules
.SUFFIXES:
@@ -365,7 +365,9 @@ o/cosmopolitan.h: \
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
- $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))
+ $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
+ $(SRCS) \
+ $(HDRS)
$(file >$@.args,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
-fno-common -include libc/integral/normalize.inc -o $@ \
diff --git a/libc/calls/calls.h b/libc/calls/calls.h
index 293bf1edc..478f985ec 100644
--- a/libc/calls/calls.h
+++ b/libc/calls/calls.h
@@ -142,6 +142,7 @@ int pause(void);
int personality(uint64_t);
int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int);
+int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_madvise(void *, uint64_t, int);
diff --git a/libc/calls/chdir.c b/libc/calls/chdir.c
index 8afec0deb..3a65fd719 100644
--- a/libc/calls/chdir.c
+++ b/libc/calls/chdir.c
@@ -28,6 +28,7 @@
*
* This does *not* update the `PWD` environment variable.
*
+ * @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
* @see fchdir()
*/
diff --git a/libc/calls/pivot_root.c b/libc/calls/pivot_root.c
new file mode 100644
index 000000000..7c81a18e4
--- /dev/null
+++ b/libc/calls/pivot_root.c
@@ -0,0 +1,33 @@
+/*-*- 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"
+
+/**
+ * Changes root mount.
+ *
+ * @raise ENOSYS on non-Linux
+ */
+int pivot_root(const char *new_root, const char *put_old) {
+ int rc;
+ rc = sys_pivot_root(new_root, put_old);
+ STRACE("pivot_root(%#s, %#s) → %d% m", new_root, put_old, rc);
+ return rc;
+}
diff --git a/libc/calls/syscall-sysv.internal.h b/libc/calls/syscall-sysv.internal.h
index 4fd97ef72..771613f61 100644
--- a/libc/calls/syscall-sysv.internal.h
+++ b/libc/calls/syscall-sysv.internal.h
@@ -68,6 +68,7 @@ i32 sys_mincore(void *, u64, unsigned char *) hidden;
i32 sys_mkdirat(i32, const char *, u32) hidden;
i32 sys_mkfifo(const char *, u32) hidden;
i32 sys_mknod(const char *, u32, u64) hidden;
+i32 sys_unmount(const char *, i32) hidden;
i32 sys_mprotect(void *, u64, i32) hidden;
i32 sys_msync(void *, u64, i32) hidden;
i32 sys_munmap(void *, u64) hidden;
@@ -76,6 +77,7 @@ i32 sys_openat(i32, const char *, i32, u32) hidden;
i32 sys_pause(void) hidden;
i32 sys_pipe(i32[hasatleast 2]) hidden;
i32 sys_pipe2(i32[hasatleast 2], u32) hidden;
+i32 sys_pivot_root(const char *, const char *) hidden;
i32 sys_pledge(const char *, const char *) hidden;
i32 sys_posix_openpt(i32) hidden;
i32 sys_renameat(i32, const char *, i32, const char *) hidden;
diff --git a/libc/calls/unmount.c b/libc/calls/unmount.c
index 46eee4447..ca4278f62 100644
--- a/libc/calls/unmount.c
+++ b/libc/calls/unmount.c
@@ -17,8 +17,8 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/mount.h"
-
-int sys_unmount(const char *, int);
+#include "libc/calls/strace.internal.h"
+#include "libc/calls/syscall-sysv.internal.h"
/**
* Unmounts file system.
@@ -30,12 +30,15 @@ int sys_unmount(const char *, int);
* The following flags may also be used, but could be set to zero at
* runtime if the underlying kernel doesn't support them.
*
- * - `MNT_DETACH`
+ * - `MNT_DETACH`: lazily unmount; Linux-only
* - `MNT_EXPIRE`
* - `UMOUNT_NOFOLLOW`
* - `MNT_BYFSID`
*
*/
int unmount(const char *target, int flags) {
- return sys_unmount(target, flags);
+ int rc;
+ rc = sys_unmount(target, flags);
+ STRACE("unmount(%#s, %#x) → %d% m", target, flags, rc);
+ return rc;
}
diff --git a/libc/runtime/isdynamicexecutable.c b/libc/runtime/isdynamicexecutable.c
new file mode 100644
index 000000000..4005c729f
--- /dev/null
+++ b/libc/runtime/isdynamicexecutable.c
@@ -0,0 +1,78 @@
+/*-*- 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/bits/bits.h"
+#include "libc/calls/calls.h"
+#include "libc/calls/struct/stat.h"
+#include "libc/elf/def.h"
+#include "libc/elf/elf.h"
+#include "libc/elf/struct/ehdr.h"
+#include "libc/elf/struct/phdr.h"
+#include "libc/errno.h"
+#include "libc/runtime/runtime.h"
+#include "libc/sysv/consts/map.h"
+#include "libc/sysv/consts/o.h"
+#include "libc/sysv/consts/prot.h"
+
+/**
+ * Returns true if ELF executable uses dynamic loading magic.
+ */
+bool IsDynamicExecutable(const char *prog) {
+ bool res;
+ Elf64_Ehdr *e;
+ Elf64_Phdr *p;
+ struct stat st;
+ int i, fd, err;
+ fd = -1;
+ err = errno;
+ e = MAP_FAILED;
+ if ((fd = open(prog, O_RDONLY)) == -1) {
+ res = false;
+ goto Finish;
+ }
+ if (fstat(fd, &st) == -1 || st.st_size < 64) {
+ res = false;
+ goto Finish;
+ }
+ if ((e = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ res = false;
+ goto Finish;
+ }
+ if (READ32LE(e->e_ident) != READ32LE(ELFMAG)) {
+ res = false;
+ goto Finish;
+ }
+ if (e->e_type == ET_DYN) {
+ res = true;
+ goto Finish;
+ }
+ for (i = 0; i < e->e_phnum; ++i) {
+ p = GetElfSegmentHeaderAddress(e, st.st_size, i);
+ if (p->p_type == PT_INTERP || p->p_type == PT_DYNAMIC) {
+ res = true;
+ goto Finish;
+ }
+ }
+ res = false;
+ goto Finish;
+Finish:
+ if (e != MAP_FAILED) munmap(e, st.st_size);
+ if (fd != -1) close(fd);
+ errno = err;
+ return res;
+}
diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h
index 6760ff9bc..94f4f60c4 100644
--- a/libc/runtime/runtime.h
+++ b/libc/runtime/runtime.h
@@ -120,6 +120,7 @@ unsigned char *GetInstructionLengths(void);
void __print_maps(void);
void __warn_if_powersave(void);
const char *__describe_os(void);
+bool IsDynamicExecutable(const char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
diff --git a/libc/stdio/mkdtemp.c b/libc/stdio/mkdtemp.c
index 02edbaa1f..6a9639420 100644
--- a/libc/stdio/mkdtemp.c
+++ b/libc/stdio/mkdtemp.c
@@ -24,7 +24,13 @@
#include "libc/sysv/errfuns.h"
/**
- * Creates temporary directory.
+ * Creates temporary directory, e.g.
+ *
+ * char path[PATH_MAX];
+ * snprintf(path, sizeof(path), "%s%s.XXXXXX",
+ * kTmpPath, program_invocation_short_name);
+ * printf("%s\n", mkdtemp(path));
+ * rmdir(path);
*
* @param template must end with XXXXXX which is replaced with
* nondeterministic base36 random data
diff --git a/libc/sysv/calls/pivot_root.s b/libc/sysv/calls/pivot_root.s
deleted file mode 100644
index a87e514e0..000000000
--- a/libc/sysv/calls/pivot_root.s
+++ /dev/null
@@ -1,2 +0,0 @@
-.include "o/libc/sysv/macros.internal.inc"
-.scall pivot_root,0xfffffffffffff09b,globl
diff --git a/libc/sysv/calls/sys_pivot_root.s b/libc/sysv/calls/sys_pivot_root.s
new file mode 100644
index 000000000..f9f832ee5
--- /dev/null
+++ b/libc/sysv/calls/sys_pivot_root.s
@@ -0,0 +1,2 @@
+.include "o/libc/sysv/macros.internal.inc"
+.scall sys_pivot_root,0xfffffffffffff09b,globl,hidden
diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh
index 5390c14ca..55f7ee433 100755
--- a/libc/sysv/syscalls.sh
+++ b/libc/sysv/syscalls.sh
@@ -209,7 +209,7 @@ scall cpuset_setaffinity 0xffffff1e8fffffff globl
scall sys_sched_rr_get_interval 0xffffff14effff094 globl hidden
scall vhangup 0xfffffffffffff099 globl
scall modify_ldt 0xfffffffffffff09a globl
-scall pivot_root 0xfffffffffffff09b globl
+scall sys_pivot_root 0xfffffffffffff09b globl hidden
scall _sysctl 0xfffffffffffff09c globl
#scall prctl 0xfffffffffffff09d globl # wrapped manually
scall sys_arch_prctl 0xfff0a50a5ffff09e globl hidden # sysarch() on bsd
diff --git a/third_party/make/job.c b/third_party/make/job.c
index 8b84fc2a2..a435abf6f 100644
--- a/third_party/make/job.c
+++ b/third_party/make/job.c
@@ -38,6 +38,15 @@ this program. If not, see . */
#include "libc/intrin/kprintf.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/runtime/runtime.h"
+#include "libc/elf/def.h"
+#include "libc/intrin/kprintf.h"
+#include "libc/elf/struct/phdr.h"
+#include "libc/elf/def.h"
+#include "libc/elf/elf.h"
+#include "libc/calls/calls.h"
+#include "libc/sysv/consts/prot.h"
+#include "libc/sysv/consts/map.h"
+#include "libc/intrin/kprintf.h"
#include "third_party/make/dep.h"
#define GOTO_SLOW \
@@ -234,6 +243,7 @@ is_bourne_compatible_shell (const char *path)
/* List of known POSIX (or POSIX-ish) shells. */
static const char *unix_shells[] = {
"build/bootstrap/cocmd.com",
+ "false",
"dash",
"sh",
"bash",
@@ -1587,20 +1597,6 @@ start_waiting_jobs (void)
}
-bool IsDynamicExecutable(const char *prog)
-{
- int fd;
- Elf64_Ehdr e;
- struct stat st;
- if ((fd = open(prog, O_RDONLY)) == -1)
- return false;
- if (read(fd, &e, sizeof(e)) != sizeof(e))
- return false;
- close(fd);
- return e.e_type == ET_DYN &&
- READ32LE(e.e_ident) == READ32LE(ELFMAG);
-}
-
bool GetPermPrefix (const char *path, char out_perm[5], const char **out_path)
{
int c, n;
@@ -1709,6 +1705,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
char outpathbuf[PATH_MAX];
const struct variable *var;
c = (struct child *)child;
+ errno = 0;
if (!lookup_variable_in_set (STRING_SIZE_TUPLE(".UNSANDBOXED"),
c->file->variables->set))
{
@@ -1717,9 +1714,11 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
if (argv[0][0] == '/' && IsDynamicExecutable (argv[0]))
{
- /* make it easier to run dynamic system executables */
+ /* weaken sandbox if user is using dynamic shared lolbjects */
+ Unveil ("/bin", "rx");
Unveil ("/lib", "rx");
Unveil ("/lib64", "rx");
+ Unveil ("/usr/bin", "rx");
Unveil ("/usr/lib", "rx");
Unveil ("/usr/lib64", "rx");
Unveil ("/usr/local/lib", "rx");
@@ -1729,6 +1728,9 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
Unveil ("/etc/ld.so.cache", "r");
Unveil ("/etc/ld.so.conf.d", "r");
Unveil ("/etc/ld.so.preload", "r");
+ Unveil ("/usr/include", "r");
+ Unveil ("/usr/share/locale", "r");
+ Unveil ("/usr/share/locale-langpack", "r");
}
else
/* permit launching actually portable executables */
@@ -1751,6 +1753,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
Unveil ("/dev/stderr", "rw");
/* unveil cosmopolitan build specific */
+ Unveil ("/tmp", "rwc");
Unveil ("o/tmp", "rwcx");
Unveil ("libc/integral", "r");
Unveil ("libc/disclaimer.inc", "r");
diff --git a/third_party/make/main.c b/third_party/make/main.c
index 3603dbe00..db78c19d0 100644
--- a/third_party/make/main.c
+++ b/third_party/make/main.c
@@ -29,6 +29,7 @@ this program. If not, see . */
#include "libc/sysv/consts/sig.h"
#include "libc/log/log.h"
#include "libc/log/log.h"
+#include "libc/log/log.h"
#include "third_party/make/getopt.h"
STATIC_STACK_SIZE(0x200000); // 2mb stack
diff --git a/third_party/make/make.mk b/third_party/make/make.mk
index 162f20a31..e610324ac 100644
--- a/third_party/make/make.mk
+++ b/third_party/make/make.mk
@@ -112,6 +112,7 @@ THIRD_PARTY_MAKE_OBJS = \
THIRD_PARTY_MAKE_DIRECTDEPS = \
LIBC_CALLS \
+ LIBC_ELF \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
@@ -123,9 +124,9 @@ THIRD_PARTY_MAKE_DIRECTDEPS = \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_TIME \
- LIBC_X \
LIBC_TINYMATH \
LIBC_UNICODE \
+ LIBC_X \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_MUSL \
THIRD_PARTY_GDTOA
diff --git a/tool/build/pledge.c b/tool/build/pledge.c
index 48c7b0997..576024f97 100644
--- a/tool/build/pledge.c
+++ b/tool/build/pledge.c
@@ -334,23 +334,6 @@ bool PathExists(const char *path) {
}
}
-bool IsDynamicExecutable(const char *prog) {
- int fd;
- Elf64_Ehdr e;
- struct stat st;
- if ((fd = open(prog, O_RDONLY)) == -1) {
- kprintf("open(%#s, O_RDONLY) failed: %m\n", prog);
- exit(13);
- }
- if (read(fd, &e, sizeof(e)) != sizeof(e)) {
- kprintf("%s: read(64) failed: %m\n", prog);
- exit(16);
- }
- close(fd);
- return e.e_type == ET_DYN && //
- READ32LE(e.e_ident) == READ32LE(ELFMAG);
-}
-
void Unveil(const char *path, const char *perm) {
if (unveil(path, perm) == -1) {
kprintf("error: unveil(%#s, %#s) failed: %m\n", path, perm);