Add .PLEDGE/.CPU/.MEMORY/etc. to Landlock Make 1.2

This commit is contained in:
Justine Tunney 2022-08-14 20:16:44 -07:00
parent 6c0bbfac4a
commit 7ab15e0b23
20 changed files with 494 additions and 329 deletions

View file

@ -18,6 +18,7 @@
*/
#include "ape/loader.h"
#define SET_EXE_FILE 0 /* needs root ;_; */
#define TROUBLESHOOT 0
#define TROUBLESHOOT_OS LINUX
@ -123,6 +124,8 @@
#define X_OK 1
#define XCR0_SSE 2
#define XCR0_AVX 4
#define PR_SET_MM 35
#define PR_SET_MM_EXE_FILE 13
#define Read32(S) \
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
@ -174,7 +177,10 @@ struct ElfPhdr {
unsigned long p_align;
};
extern char ehdr[];
extern char _end[];
static void *syscall;
static char relocated;
static struct PathSearcher ps;
extern char __syscall_loader[];
@ -182,7 +188,7 @@ static int ToLower(int c) {
return 'A' <= c && c <= 'Z' ? c + ('a' - 'A') : c;
}
static char *MemCpy(char *d, const char *s, unsigned long n) {
char *MemCpy(char *d, const char *s, unsigned long n) {
unsigned long i = 0;
for (; i < n; ++i) d[i] = s[i];
return d + n;
@ -373,6 +379,26 @@ __attribute__((__noinline__)) static long Mmap(long addr, long size, int prot,
return ax;
}
static int MunmapLinux(const void *addr, unsigned long size) {
int ax;
asm volatile("syscall"
: "=a"(ax)
: "0"(11), "D"(addr), "S"(size)
: "rcx", "r11", "memory");
return ax;
}
static int PrctlLinux(int op, long a, long b, long c, long d) {
int rc;
asm volatile("mov\t%5,%%r10\n\t"
"mov\t%6,%%r8\n\t"
"syscall"
: "=a"(rc)
: "0"(157), "D"(op), "S"(a), "d"(b), "g"(c), "g"(d)
: "rcx", "r8", "r10", "r11", "memory");
return rc;
}
static void Emit(int os, const char *s) {
Write(2, s, StrLen(s), os);
}
@ -539,6 +565,23 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
if (!code) {
Pexit(os, exe, 0, "ELF needs PT_LOAD phdr w/ PF_X");
}
#if SET_EXE_FILE
// change /proc/pid/exe to new executable path
if (IsLinux() && relocated) {
MunmapLinux((char *)0x200000, (long)(_end - ehdr));
PrctlLinux(PR_SET_MM, PR_SET_MM_EXE_FILE, fd, 0, 0);
}
#endif
if (relocated) {
int ax;
asm volatile("syscall"
: "=a"(ax)
: "0"(1), "D"(1), "S"("hello\n"), "d"(6)
: "rcx", "r11", "memory");
}
Close(fd, os);
// authorize only the loaded program to issue system calls. if this
@ -584,7 +627,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
struct ApeLoader *handoff) {
int rc;
long *auxv;
struct ElfEhdr *ehdr;
struct ElfEhdr *eh;
int c, i, fd, os, argc;
char *p, *exe, *prog, **argv, **envp, *page;
static union {
@ -630,7 +673,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
fd = handoff->fd;
exe = handoff->prog;
page = handoff->page;
ehdr = (struct ElfEhdr *)handoff->page;
eh = (struct ElfEhdr *)handoff->page;
} else {
// detect openbsd
@ -653,6 +696,20 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
os = LINUX;
}
#if SET_EXE_FILE
if (IsLinux() && !relocated) {
char *b1 = (char *)0x200000;
char *b2 = (char *)0x300000;
void (*pApeLoader)(long, long *, char, struct ApeLoader *);
Mmap((long)b2, (long)(_end - ehdr), PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, os);
relocated = 1;
MemCpy(b2, b1, (long)(_end - ehdr));
pApeLoader = (void *)((char *)&ApeLoader - b1 + b2);
pApeLoader(di, sp, dl, handoff);
}
#endif
// we can load via shell, shebang, or binfmt_misc
if (argc >= 3 && !StrCmp(argv[1], "-")) {
// if the first argument is a hyphen then we give the user the
@ -686,7 +743,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
}
page = u.p;
ehdr = &u.ehdr;
eh = &u.ehdr;
}
#if TROUBLESHOOT
@ -726,7 +783,7 @@ __attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl,
page[i++] = c;
}
if (i >= 64 && Read32(page) == Read32("\177ELF")) {
Spawn(os, exe, fd, sp, page, ehdr);
Spawn(os, exe, fd, sp, page, eh);
}
}

View file

@ -32,7 +32,8 @@ SECTIONS {
*(.bss)
. = ALIGN(4096);
}
memsz = . - ehdr;
_end = .;
memsz = _end - ehdr;
/DISCARD/ : {
*(.*)
}

View file

@ -45,33 +45,33 @@ int main(int argc, char *argv[]) {
1. / 65536 * si.loads[1], //
1. / 65536 * si.loads[2]); //
FormatMemorySize(ibuf, si.totalram);
FormatMemorySize(ibuf, si.totalram, 1024);
printf("%-16s %s\n", "totalram", ibuf);
FormatMemorySize(ibuf, si.freeram);
FormatMemorySize(ibuf, si.freeram, 1024);
printf("%-16s %s\n", "freeram", ibuf);
FormatMemorySize(ibuf, si.sharedram);
FormatMemorySize(ibuf, si.sharedram, 1024);
printf("%-16s %s\n", "sharedram", ibuf);
FormatMemorySize(ibuf, si.bufferram);
FormatMemorySize(ibuf, si.bufferram, 1024);
printf("%-16s %s\n", "bufferram", ibuf);
FormatMemorySize(ibuf, si.totalswap);
FormatMemorySize(ibuf, si.totalswap, 1024);
printf("%-16s %s\n", "totalswap", ibuf);
FormatMemorySize(ibuf, si.freeswap);
FormatMemorySize(ibuf, si.freeswap, 1024);
printf("%-16s %s\n", "freeswap", ibuf);
printf("%-16s %lu\n", "processes", si.procs);
FormatMemorySize(ibuf, si.totalhigh);
FormatMemorySize(ibuf, si.totalhigh, 1024);
printf("%-16s %s\n", "totalhigh", ibuf);
FormatMemorySize(ibuf, si.freehigh);
FormatMemorySize(ibuf, si.freehigh, 1024);
printf("%-16s %s\n", "freehigh", ibuf);
FormatMemorySize(ibuf, si.mem_unit);
FormatMemorySize(ibuf, si.mem_unit, 1024);
printf("%-16s %s\n", "mem_unit", ibuf);
//

View file

@ -825,7 +825,7 @@ static privileged void *MemCpy(void *d, const void *s, unsigned long n) {
return (char *)d + n;
}
static privileged char *FixCpy(char p[17], uint64_t x, uint8_t k) {
static privileged char *FixCpy(char p[17], uint64_t x, int k) {
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0';
return p;
@ -868,7 +868,6 @@ static privileged void Log(const char *s, ...) {
static privileged int Prctl(int op, long a, void *b, long c, long d) {
int rc;
va_list va;
asm volatile("mov\t%5,%%r10\n\t"
"mov\t%6,%%r8\n\t"
"syscall"

View file

@ -19,26 +19,26 @@
#include "libc/fmt/itoa.h"
#include "libc/macros.internal.h"
static const struct {
char suffix;
uint64_t size;
} kUnits[] = {
{'e', 1024ULL * 1024 * 1024 * 1024 * 1024 * 1024},
{'p', 1024ULL * 1024 * 1024 * 1024 * 1024},
{'t', 1024ULL * 1024 * 1024 * 1024},
{'g', 1024ULL * 1024 * 1024},
{'m', 1024ULL * 1024},
{'k', 1024ULL},
};
/**
* Represents size of memory readably.
*
* @param p is output buffer
* @param b should be 1024 or 1000
* @return pointer to nul byte
*/
char *FormatMemorySize(char *p, uint64_t x) {
char *FormatMemorySize(char *p, uint64_t x, uint64_t b) {
int i, suffix;
struct {
char suffix;
uint64_t size;
} kUnits[] = {
{'e', b * b * b * b * b * b},
{'p', b * b * b * b * b},
{'t', b * b * b * b},
{'g', b * b * b},
{'m', b * b},
{'k', b},
};
for (suffix = i = 0; i < ARRAYLEN(kUnits); ++i) {
if (x >= kUnits[i].size * 9) {
x = (x + kUnits[i].size / 2) / kUnits[i].size;

View file

@ -21,7 +21,7 @@ char *FormatFlex64(char[hasatleast 24], int64_t, char);
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);
char *FormatMemorySize(char *, uint64_t);
char *FormatMemorySize(char *, uint64_t, uint64_t);
#ifndef __STRICT_ANSI__
size_t int128toarray_radix10(int128_t, char *);

View file

@ -158,7 +158,7 @@ static bool IsSockaddrAllowed(struct sockaddr_storage *addr) {
}
if (addr->ss_family == AF_INET) {
ip = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
if (!IsPublicIp(ip)) {
if (IsPrivateIp(ip) || IsLoopbackIp(ip)) {
return true;
} else {
kprintf("warning: attempted to communicate with public ip "

View file

@ -35,7 +35,7 @@ void SetUpOnce(void) {
TEST(setsockopt, SO_RCVTIMEO) {
char buf[32];
struct timeval tv = {0, 10000};
struct sockaddr_in sa = {AF_INET};
struct sockaddr_in sa = {AF_INET, 0, {htonl(0x7f000001)}};
EXPECT_SYS(0, 3, socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
EXPECT_SYS(0, 0, setsockopt(3, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)));
EXPECT_SYS(0, 0, bind(3, &sa, sizeof(struct sockaddr_in)));

View file

@ -1,188 +0,0 @@
This directory contains the 4.3 release of GNU Make.
See the file NEWS for the user-visible changes from previous releases.
In addition, there have been bugs fixed.
Please check the system-specific notes below for any caveats related to your
operating system.
If you are trying to build GNU make from a Git clone rather than a downloaded
source distribution, see the README.git file for instructions.
For source distribution building and installation instructions, see the file
INSTALL.
If you need to build GNU Make and have no other 'make' program to use, you can
use the shell script 'build.sh' instead. To do this, first run 'configure' as
described in INSTALL. Then, instead of typing 'make' to build the program,
type 'sh build.sh'. This should compile the program in the current directory.
Then you will have a Make program that you can use for './make install', or
whatever else.
Some systems' Make programs cannot process the Makefile for GNU Make. If you
get errors from your system's Make when building GNU Make, try using
'build.sh' instead.
GNU Make is free software. See the file COPYING for copying conditions.
GNU Make is copyright by the Free Software Foundation. Copyright notices
condense sequential years into a range; e.g. "1987-1994" means all years
from 1987 to 1994 inclusive.
Downloading
-----------
GNU Make can be obtained in many different ways. See a description here:
http://www.gnu.org/software/software.html
Documentation
-------------
GNU make is fully documented in the GNU Make manual, which is contained
in this distribution as the file make.texinfo. You can also find
on-line and preformatted (PostScript and DVI) versions at the FSF's web
site. There is information there about ordering hardcopy documentation.
http://www.gnu.org/
http://www.gnu.org/doc/doc.html
http://www.gnu.org/manual/manual.html
Development
-----------
GNU Make development is hosted by Savannah, the FSF's online development
management tool. Savannah is here:
http://savannah.gnu.org
And the GNU Make development page is here:
http://savannah.gnu.org/projects/make/
You can find most information concerning the development of GNU Make at
this site.
Bug Reporting
-------------
You can send GNU make bug reports to <bug-make@gnu.org>. Please see the
section of the GNU make manual entitled 'Problems and Bugs' for
information on submitting useful and complete bug reports.
You can also use the online bug tracking system in the Savannah GNU Make
project to submit new problem reports or search for existing ones:
http://savannah.gnu.org/bugs/?group=make
If you need help using GNU make, try these forums:
help-make@gnu.org
help-utils@gnu.org
news:gnu.utils.help
news:gnu.utils.bug
Git Access
----------
The GNU make source repository is available via Git from the GNU Savannah Git
server; look here for details:
http://savannah.gnu.org/git/?group=make
Please note: you won't be able to build GNU make from Git without installing
appropriate maintainer's tools, such as GNU m4, automake, autoconf, Perl, GNU
make, and GCC.
See the README.git file for instructions on how to build GNU make once these
tools are available. We make no guarantees about the contents or quality of
the latest code in the Git repository: it is not unheard of for code that is
known to be broken to be checked in. Use at your own risk.
System-specific Notes
---------------------
It has been reported that the XLC 1.2 compiler on AIX 3.2 is buggy such
that if you compile make with 'cc -O' on AIX 3.2, it will not work
correctly. It is said that using 'cc' without '-O' does work.
The standard /bin/sh on SunOS 4.1.3_U1 and 4.1.4 is broken and cannot be
used to configure GNU make. Please install a different shell such as
bash or pdksh in order to run "configure". See this message for more
information:
http://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html
One area that is often a problem in configuration and porting is the code
to check the system's current load average. To make it easier to test and
debug this code, you can do 'make check-loadavg' to see if it works
properly on your system. (You must run 'configure' beforehand, but you
need not build Make itself to run this test.)
Another potential source of porting problems is the support for large
files (LFS) in configure for those operating systems that provide it.
Please report any bugs that you find in this area. If you run into
difficulties, then as a workaround you should be able to disable LFS by
adding the '--disable-largefile' option to the 'configure' script.
On systems that support micro- and nano-second timestamp values and
where stat(2) provides this information, GNU make will use it when
comparing timestamps to get the most accurate possible result. However,
note that many current implementations of tools that *set* timestamps do
not preserve micro- or nano-second granularity. This means that "cp -p"
and other similar tools (tar, etc.) may not exactly duplicate timestamps
with micro- and nano-second granularity on some systems. If your build
system contains rules that depend on proper behavior of tools like "cp
-p", you should consider using the .LOW_RESOLUTION_TIME pseudo-target to
force make to treat them properly. See the manual for details.
Ports
-----
- See README.customs for details on integrating GNU make with the
Customs distributed build environment from the Pmake distribution.
- See README.VMS for details about GNU Make on OpenVMS.
- See README.Amiga for details about GNU Make on AmigaDOS.
- See README.W32 for details about GNU Make on Windows NT, 95, or 98.
- See README.DOS for compilation instructions on MS-DOS and MS-Windows
using DJGPP tools.
A precompiled binary of the MSDOS port of GNU Make is available as part
of DJGPP; see the WWW page http://www.delorie.com/djgpp/ for more
information.
The Cygwin project maintains its own port of GNU make. That port may have
patches which are not present in this version. If you are using Cygwin
you should use their version of GNU make, and if you have questions about
it you should start by asking on those mailing lists and forums.
Please note there are two _separate_ ports of GNU make for Microsoft
systems: a native Windows tool built with (for example) MSVC or Cygwin,
and a DOS-based tool built with DJGPP. Please be sure you are looking
at the right README!
-------------------------------------------------------------------------------
Copyright (C) 1988-2020 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,12 +1,29 @@
DESCRIPTION
Landlock Make is a fork of GNU Make that adds support for automatic
sandboxing, resource limits, and network access restrictions.
ORIGIN
GNU Make 4.3
http://ftp.gnu.org/gnu/make/make-4.3.tar.gz
LICENSE
GNU GPL version 3 or later
http://gnu.org/licenses/gpl.html
LOCAL CHANGES
- Remove portability torture code
- Add support for Landlock LSM sandboxing
- Add .UNSANDBOXED variable to disable it
- Add .UNVEIL variable which works like .EXTRA_PREREQS
- .INTERNET variable to allow internet access
- .PLEDGE variable which restricts system calls
- .UNVEIL variable which controls Landlock LSM
- .STRICT variable to disable implicit unveiling
- .UNSANDBOXED variable to disable pledge / unveil
- .CPU variable which tunes CPU rlimit in seconds
- .MEMORY variable for virtual memory limit, e.g. 512m
- .FSIZE variable which tunes max file size, e.g. 1g
- .NPROC variable which tunes fork() / clone() limit
- Do automatic setup and teardown of TMPDIR per rule
- Remove code that forces slow path if not using /bin/sh
- Remove 200,000 lines of VAX/OS2/DOS/AMIGA/etc. code

View file

@ -1640,7 +1640,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
child.output.err = errfd;
child.environment = envp;
pid = child_execute_job (&child, 1, command_argv);
pid = child_execute_job (&child, 1, command_argv, false);
free (child.cmd_name);
}

365
third_party/make/job.c vendored
View file

@ -22,23 +22,31 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
/**/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/pledge.h"
#include "libc/calls/pledge.internal.h"
#include "libc/calls/struct/bpf.h"
#include "libc/calls/struct/filter.h"
#include "libc/calls/struct/seccomp.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.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/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/promises.internal.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/log.h"
#include "libc/log/rop.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/kcpuids.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/audit.h"
@ -49,6 +57,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/sysv/consts/prot.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/libcxx/math.h"
#include "third_party/make/commands.h"
#include "third_party/make/dep.h"
#include "third_party/make/os.h"
@ -75,8 +84,6 @@ int batch_mode_shell = 0;
#define WAIT_T int
bool g_strict;
/* Different systems have different requirements for pid_t.
Plus we have to support gettext string translation... Argh. */
static const char *
@ -377,19 +384,39 @@ child_error (struct child *child,
/* [jart] manage temporary directories per rule */
bool
parse_bool (const char *s)
{
while (isspace (*s))
++s;
if (isdigit (*s))
return !! atoi (s);
return startswithi (s, "true");
}
const char *
get_target_variable (const char *name,
size_t length,
struct file *file,
const char *dflt)
{
const struct variable *var;
if ((file &&
((var = lookup_variable_in_set (name, length,
file->variables->set)) ||
(file->pat_variables &&
(var = lookup_variable_in_set (name, length,
file->pat_variables->set))))) ||
(var = lookup_variable (name, length)))
return variable_expand (var->value);
else
return dflt;
}
const char *
get_tmpdir (struct file *file)
{
const struct variable *var;
if ((var = lookup_variable_in_set (STRING_SIZE_TUPLE("TMPDIR"),
file->variables->set)) ||
(file->pat_variables &&
(var = lookup_variable_in_set (STRING_SIZE_TUPLE("TMPDIR"),
file->pat_variables->set))) ||
(var = lookup_variable (STRING_SIZE_TUPLE("TMPDIR"))))
return variable_expand (var->value);
else
return kTmpPath;
return get_target_variable (STRING_SIZE_TUPLE("TMPDIR"), file, 0);
}
char *
@ -1154,7 +1181,7 @@ start_job_command (struct child *child)
parent_environ = environ;
jobserver_pre_child (flags & COMMANDS_RECURSE);
child->pid = child_execute_job ((struct childbase *)child,
child->good_stdin, argv);
child->good_stdin, argv, true);
environ = parent_environ; /* Restore value child may have clobbered. */
jobserver_post_child (flags & COMMANDS_RECURSE);
}
@ -1277,7 +1304,8 @@ new_job (struct file *file)
c->sh_batch_file = NULL;
/* [jart] manage temporary directories per rule */
if ((c->tmpdir = new_tmpdir (get_tmpdir (file), file)))
if ((c->tmpdir = get_tmpdir (file)) &&
(c->tmpdir = new_tmpdir (c->tmpdir, file)))
{
var = define_variable_for_file ("TMPDIR", 6, c->tmpdir,
o_override, 0, file);
@ -1764,22 +1792,98 @@ unveil_variable (const struct variable *var)
return -1;
}
bool
Vartoi (const struct variable *var)
int
get_base_cpu_freq_mhz (void)
{
return var && atoi (variable_expand (var->value));
return KCPUIDS(16H, EAX) & 0x7fff;
}
void
set_cpu_limit (int secs)
{
int mhz, lim;
struct rlimit rlim;
if (secs <= 0) return;
if (IsWindows()) return;
if (!(mhz = get_base_cpu_freq_mhz())) return;
lim = ceil(3100. / mhz * secs);
rlim.rlim_cur = lim;
rlim.rlim_max = lim + 1;
if (setrlimit(RLIMIT_CPU, &rlim) == -1)
{
if (getrlimit(RLIMIT_CPU, &rlim) == -1)
return;
if (lim < rlim.rlim_cur)
{
rlim.rlim_cur = lim;
setrlimit(RLIMIT_CPU, &rlim);
}
}
}
void
set_fsz_limit (long n)
{
struct rlimit rlim;
if (n <= 0) return;
if (IsWindows()) return;
rlim.rlim_cur = n;
rlim.rlim_max = n << 1;
if (setrlimit(RLIMIT_FSIZE, &rlim) == -1)
{
if (getrlimit(RLIMIT_FSIZE, &rlim) == -1)
return;
rlim.rlim_cur = n;
setrlimit(RLIMIT_FSIZE, &rlim);
}
}
void
set_mem_limit (long n)
{
struct rlimit rlim = {n, n};
if (n <= 0) return;
if (IsWindows() || IsXnu()) return;
setrlimit(RLIMIT_AS, &rlim);
}
void
set_pro_limit (long n)
{
struct rlimit rlim = {n, n};
if (n <= 0) return;
setrlimit(RLIMIT_NPROC, &rlim);
}
static struct sysinfo g_sysinfo;
__attribute__((__constructor__)) static void
get_sysinfo (void)
{
int e = errno;
sysinfo (&g_sysinfo);
errno = e;
}
static bool internet;
static char *promises;
/* POSIX:
Create a child process executing the command in ARGV.
Returns the PID or -1. */
pid_t
child_execute_job (struct childbase *child, int good_stdin, char **argv)
child_execute_job (struct childbase *child,
int good_stdin,
char **argv,
bool is_build_rule)
{
const int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
struct dep *d;
bool strict;
bool sandboxed;
bool unsandboxed;
struct child *c;
unsigned long ipromises;
char pathbuf[PATH_MAX];
char outpathbuf[PATH_MAX];
int fdout = FD_STDOUT;
@ -1808,28 +1912,145 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
if (stack_limit.rlim_cur)
setrlimit (RLIMIT_STACK, &stack_limit);
g_strict = Vartoi (lookup_variable (STRING_SIZE_TUPLE (".STRICT")));
intptr_t loc = (intptr_t)child; /* we can cast if it's on the heap ;_; */
if (!(GetStackAddr() < loc && loc < GetStackAddr() + GetStackSize())) {
/* Tell build rules apart from $(shell foo). */
if (is_build_rule) {
c = (struct child *)child;
} else {
c = 0;
}
sandboxed = (
!Vartoi (lookup_variable
(STRING_SIZE_TUPLE(".UNSANDBOXED"))) &&
(!c || !Vartoi (lookup_variable_in_set
(STRING_SIZE_TUPLE(".UNSANDBOXED"),
c->file->variables->set))) &&
(!c || !c->file->pat_variables ||
!Vartoi (lookup_variable_in_set
(STRING_SIZE_TUPLE(".UNSANDBOXED"),
c->file->pat_variables->set))));
internet = parse_bool (get_target_variable
(STRING_SIZE_TUPLE(".INTERNET"),
c ? c->file : 0, "0"));
/* resolve command into executable path */
if (!g_strict || !sandboxed)
unsandboxed = parse_bool (get_target_variable
(STRING_SIZE_TUPLE(".UNSANDBOXED"),
c ? c->file : 0, "0"));
if (c)
{
sandboxed = !unsandboxed;
strict = parse_bool (get_target_variable
(STRING_SIZE_TUPLE(".STRICT"),
c->file, "0"));
}
else
{
sandboxed = false;
strict = false;
}
if (!unsandboxed)
{
promises = emptytonull (get_target_variable
(STRING_SIZE_TUPLE(".PLEDGE"),
c ? c->file : 0, 0));
if (promises)
promises = xstrdup (promises);
if (ParsePromises (promises, &ipromises))
{
OSS (error, NILF, "%s: invalid .PLEDGE string: %s",
argv[0], strerror (errno));
_Exit (127);
}
}
else
{
promises = NULL;
ipromises = 0;
}
DB (DB_JOBS,
(_("Executing %s for %s%s%s%s\n"),
argv[0], c ? c->file->name : "$(shell)",
sandboxed ? " with sandboxing" : " without sandboxing",
strict ? " in .STRICT mode" : "",
internet ? " with internet access" : ""));
/* [jart] Set cpu seconds quota. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".CPU"),
c ? c->file : 0, 0)))
{
int secs;
secs = atoi (s);
DB (DB_JOBS, (_("Setting cpu limit of %d seconds\n"), secs));
set_cpu_limit (secs);
}
/* [jart] Set virtual memory quota. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".MEMORY"),
c ? c->file : 0, 0)))
{
long bytes;
char buf[16];
if (!strchr (s, '%'))
bytes = sizetol (s, 1024);
else
bytes = strtod (s, 0) / 100. * g_sysinfo.totalram;
DB (DB_JOBS, (_("Setting virtual memory limit of %s\n"),
(FormatMemorySize (buf, bytes, 1024), buf)));
set_mem_limit (bytes);
}
/* [jart] Set file size limit. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".FSIZE"),
c ? c->file : 0, 0)))
{
long bytes;
char buf[16];
bytes = sizetol (s, 1000);
DB (DB_JOBS, (_("Setting file size limit of %s\n"),
(FormatMemorySize (buf, bytes, 1000), buf)));
set_fsz_limit (bytes);
}
/* [jart] Set process limit. */
if ((s = get_target_variable (STRING_SIZE_TUPLE(".NPROC"),
c ? c->file : 0, 0)))
{
int procs;
if ((procs = atoi (s)) > 0)
{
DB (DB_JOBS, (_("Setting process limit to %d + %d preexisting\n"),
procs, g_sysinfo.procs));
set_pro_limit (procs + g_sysinfo.procs);
}
}
/* [jart] Prevent builds from talking to the Internet. */
if (internet)
DB (DB_JOBS, (_("Allowing Internet access\n")));
else if (!(~ipromises & (1ul << PROMISE_INET)) &&
!(~ipromises & (1ul << PROMISE_DNS)))
DB (DB_JOBS, (_("Internet access will be blocked by pledge\n")));
else
{
e = errno;
if (!nointernet())
DB (DB_JOBS, (_("Blocked Internet access with seccomp ptrace\n")));
else
{
if (errno = EPERM)
{
errno = e;
DB (DB_JOBS, (_("Can't block Internet if already traced\n")));
}
else if (errno == ENOSYS)
{
errno = e;
DB (DB_JOBS, (_("Need SECCOMP ptrace() to block Internet\n")));
}
else
{
OSS (error, NILF, "%s: failed to block internet access: %s",
argv[0], strerror (errno));
_Exit (127);
}
}
}
/* [jart] Resolve command into executable path. */
if (!strict || !sandboxed)
{
if ((s = commandv (argv[0], pathbuf, sizeof (pathbuf))))
argv[0] = s;
@ -1841,15 +2062,13 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
}
}
/* [jart] sandbox command based on prerequisites */
/* [jart] Sandbox build rule commands based on prerequisites. */
if (c)
{
errno = 0;
if (sandboxed)
{
DB (DB_JOBS, (_("Sandboxing %s\n"), c->file->name));
if (!g_strict && argv[0][0] == '/' && IsDynamicExecutable (argv[0]))
if (!strict && argv[0][0] == '/' && IsDynamicExecutable (argv[0]))
{
/*
* weaken sandbox if user is using dynamic shared lolbjects
@ -1883,6 +2102,8 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
* only if the ape loader exists on a well-known path.
*/
e = errno;
DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"),
"/usr/bin/ape", "rx"));
if (unveil ("/usr/bin/ape", "rx") == -1)
{
char *s, *t;
@ -1902,15 +2123,15 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
}
}
/* unveil executable */
/* Unveil executable. */
RETURN_ON_ERROR (Unveil (argv[0], "rx"));
/* unveil temporary directory */
/* Unveil temporary directory. */
if (c->tmpdir)
RETURN_ON_ERROR (Unveil (c->tmpdir, "rwcx"));
/* unveil lazy mode files */
if (!g_strict)
/* Unveil lazy mode files. */
if (!strict)
{
RETURN_ON_ERROR (Unveil ("/tmp", "rwc"));
RETURN_ON_ERROR (Unveil ("/dev/zero", "r"));
@ -1922,6 +2143,50 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
RETURN_ON_ERROR (Unveil ("/etc/hosts", "r"));
}
/* Unveil .PLEDGE = tmppath. */
if (!strict && promises && (~ipromises & (1ul << PROMISE_TMPPATH)))
RETURN_ON_ERROR (Unveil ("/tmp", "rwc"));
/* Unveil .PLEDGE = vminfo. */
if (promises && (~ipromises & (1ul << PROMISE_VMINFO)))
{
RETURN_ON_ERROR (Unveil ("/proc/stat", "r"));
RETURN_ON_ERROR (Unveil ("/proc/meminfo", "r"));
RETURN_ON_ERROR (Unveil ("/proc/cpuinfo", "r"));
RETURN_ON_ERROR (Unveil ("/proc/diskstats", "r"));
RETURN_ON_ERROR (Unveil ("/proc/self/maps", "r"));
RETURN_ON_ERROR (Unveil ("/sys/devices/system/cpu", "r"));
}
/* Unveil .PLEDGE = tty. */
if (promises && (~ipromises & (1ul << PROMISE_TTY)))
{
RETURN_ON_ERROR (Unveil (ttyname(0), "rw"));
RETURN_ON_ERROR (Unveil ("/dev/tty", "rw"));
RETURN_ON_ERROR (Unveil ("/dev/console", "rw"));
RETURN_ON_ERROR (Unveil ("/etc/terminfo", "r"));
RETURN_ON_ERROR (Unveil ("/usr/lib/terminfo", "r"));
RETURN_ON_ERROR (Unveil ("/usr/share/terminfo", "r"));
}
/* Unveil .PLEDGE = dns. */
if (promises && (~ipromises & (1ul << PROMISE_DNS)))
{
RETURN_ON_ERROR (Unveil ("/etc/hosts", "r"));
RETURN_ON_ERROR (Unveil ("/etc/hostname", "r"));
RETURN_ON_ERROR (Unveil ("/etc/services", "r"));
RETURN_ON_ERROR (Unveil ("/etc/protocols", "r"));
RETURN_ON_ERROR (Unveil ("/etc/resolv.conf", "r"));
}
/* Unveil .PLEDGE = inet. */
if (promises && (~ipromises & (1ul << PROMISE_INET)))
RETURN_ON_ERROR (Unveil ("/etc/ssl/certs/ca-certificates.crt", "r"));
/* Unveil .PLEDGE = rpath. */
if (promises && (~ipromises & (1ul << PROMISE_INET)))
RETURN_ON_ERROR (Unveil ("/proc/filesystems", "r"));
/*
* unveils target output file
*
@ -2017,6 +2282,20 @@ exec_command (char **argv, char **envp)
/* Be the user, permanently. */
child_access ();
/* Restrict system calls. */
if (promises)
{
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM;
DB (DB_JOBS, (_("Pledging %s\n"), promises));
promises = xstrcat (promises, " prot_exec exec");
if (pledge (promises, promises))
{
OSS (error, NILF, "pledge(%s) failed: %s",
promises, strerror (errno));
_Exit (127);
}
}
/* Run the program. */
environ = envp;
execv (argv[0], argv);

View file

@ -71,7 +71,7 @@ void start_waiting_jobs (void);
char **construct_command_argv (char *line, char **restp, struct file *file,
int cmd_flags, char** batch_file);
pid_t child_execute_job (struct childbase *child, int good_stdin, char **argv);
pid_t child_execute_job (struct childbase *, int, char **, bool);
#ifdef _AMIGA
void exec_command (char **argv) NORETURN;

View file

@ -14,40 +14,36 @@ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
/* clang-format off */
#include "third_party/make/makeint.inc"
#include "third_party/make/os.h"
/**/
#include "third_party/make/filedef.h"
#include "third_party/make/os.h"
/**/
#include "third_party/make/dep.h"
#include "third_party/make/variable.h"
#include "third_party/make/job.h"
#include "third_party/make/variable.h"
/**/
#include "third_party/make/commands.h"
#include "third_party/make/rule.h"
#include "third_party/make/debug.h"
#include "libc/runtime/stack.h"
#include "libc/limits.h"
#include "libc/sysv/consts/sig.h"
#include "libc/log/log.h"
#include "libc/log/log.h"
#include "libc/log/log.h"
#include "libc/sock/sock.h"
#include "libc/dce.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/calls/struct/seccomp.h"
#include "libc/calls/struct/bpf.h"
#include "libc/sysv/consts/audit.h"
#include "libc/calls/struct/seccomp.h"
#include "libc/sysv/consts/pr.h"
#include "third_party/make/rule.h"
/**/
#include "libc/calls/calls.h"
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/calls/struct/bpf.h"
#include "libc/calls/struct/filter.h"
#include "libc/calls/struct/seccomp.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/log/log.h"
#include "libc/log/log.h"
#include "libc/runtime/stack.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/audit.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/sig.h"
#include "third_party/make/getopt.h"
// clang-format off
STATIC_STACK_SIZE(0x200000); // 2mb stack
@ -985,10 +981,6 @@ main (int argc, char **argv, char **envp)
unsigned int syncing = 0;
int argv_slots;
// block internet access
if (!getenv("MAKE_RESTARTS"))
nointernet ();
/* Useful for attaching debuggers, etc. */
SPIN ("main-entry");
@ -2982,7 +2974,7 @@ print_version (void)
/* Do it only once. */
return;
printf ("%sLandlock Make 1.1.1 (GNU Make %s)\n", precede, version_string);
printf ("%sLandlock Make 1.2 (GNU Make %s)\n", precede, version_string);
if (!remote_description || *remote_description == '\0')
printf (_("%sBuilt for %s\n"), precede, make_host);

View file

@ -254,7 +254,9 @@ static int OpMunmap(struct Machine *m, int64_t virt, uint64_t size) {
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t offset) {
int e;
void *tmp;
ssize_t rc;
uint64_t key;
VERBOSEF("MMAP%s %012lx %,ld %#x %#x %d %#lx", GetSimulated(), virt, size,
prot, flags, fd, offset);
@ -277,7 +279,13 @@ static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
/* TODO: lazy file mappings */
CHECK_NOTNULL((tmp = malloc(size)));
CHECK_EQ(size, pread(fd, tmp, size, offset));
for (e = errno;;) {
rc = pread(fd, tmp, size, offset);
if (rc != -1) break;
CHECK_EQ(EINTR, errno);
errno = e;
}
CHECK_EQ(size, rc);
VirtualRecvWrite(m, virt, tmp, size);
free(tmp);
}

View file

@ -7104,7 +7104,7 @@ static void HandleShutdown(void) {
}
// this function coroutines with linenoise
static int EventLoop(int ms) {
int EventLoop(int ms) {
struct timespec t;
DEBUGF("(repl) event loop");
while (!terminated) {

View file

@ -7,9 +7,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/intrin/bits.h"
#include "libc/calls/internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/bits.h"
#include "libc/macros.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/stdio/stdio.h"
@ -30,7 +30,7 @@ uint64_t last;
void plan2(uint64_t addr, uint64_t end, const char *name) {
char sz[32];
FormatMemorySize(sz, end-addr+1);
FormatMemorySize(sz, end-addr+1, 1024);
printf("%08x-%08x %-6s %s\n", addr>>16, end>>16, sz, name);
}