Re: Exec pledges

2017-10-08 Thread Theo de Raadt
> I wrote some patches to allow pledging across execs.
> Currently, the exec pledge passes down the process tree.
> 
> The initial version simply inherited the current pledge when
> execing with the `pledge("rexec")` promise, but after
> discussing with Theo at EuroBSD, a better design was
> suggested.  Because directory pledges are going to be their
> own system call, we can repurpose the second argument of
> pledge as the "exec pledge".

I have a more substantial version of this change, but I am still
iterating the design by studying impact throughout the tree.  Not
ready to share widely yet.



Re: Exec pledges

2017-10-08 Thread Hiltjo Posthuma
On Sun, Oct 08, 2017 at 02:43:48AM -0700, Ori Bernstein wrote:
> And pax, because I can
> 
> 
> 
> 
> diff --git bin/pax/ar_io.c bin/pax/ar_io.c
> index 40a6492405e..ce53a9ae51b 100644
> --- bin/pax/ar_io.c
> +++ bin/pax/ar_io.c
> @@ -1281,6 +1281,11 @@ ar_start_gzip(int fd, const char *path, int wr)
>   /* System compressors are more likely to use pledge(2) */
>   putenv("PATH=/usr/bin:/usr/local/bin");
>  
> + /* Restrict them to sane pledges */
> + if (pledge(NULL, "stdio rpath wpath cpath fattr chown "
> + "prot_exec") == -1)
> + err(1, "pledge");
> +

The pledge(2) arguments are passed in the wrong order here I think.
pledge(NULL, ...) to pledge(..., NULL).

>   if (execlp(path, path, gzip_flags, (char *)NULL) < 0)
>   err(1, "could not exec %s", path);
>   /* NOTREACHED */
> 

-- 
Kind regards,
Hiltjo



Re: Exec pledges

2017-10-08 Thread Ori Bernstein
And pax, because I can




diff --git bin/pax/ar_io.c bin/pax/ar_io.c
index 40a6492405e..ce53a9ae51b 100644
--- bin/pax/ar_io.c
+++ bin/pax/ar_io.c
@@ -1281,6 +1281,11 @@ ar_start_gzip(int fd, const char *path, int wr)
/* System compressors are more likely to use pledge(2) */
putenv("PATH=/usr/bin:/usr/local/bin");
 
+   /* Restrict them to sane pledges */
+   if (pledge(NULL, "stdio rpath wpath cpath fattr chown "
+   "prot_exec") == -1)
+   err(1, "pledge");
+
if (execlp(path, path, gzip_flags, (char *)NULL) < 0)
err(1, "could not exec %s", path);
/* NOTREACHED */



Re: Exec pledges

2017-10-08 Thread Ori Bernstein
Slowcgi. Because if someone could fool it into
running the wrong binary, the outcome may be
suboptimal.




diff --git usr.sbin/slowcgi/slowcgi.8 usr.sbin/slowcgi/slowcgi.8
index d3ab4030bed..f8f07630204 100644
--- usr.sbin/slowcgi/slowcgi.8
+++ usr.sbin/slowcgi/slowcgi.8
@@ -24,6 +24,7 @@
 .Nm
 .Op Fl d
 .Op Fl p Ar path
+.Op Fl P Ar pledge
 .Op Fl s Ar socket
 .Op Fl u Ar user
 .Sh DESCRIPTION
@@ -72,6 +73,9 @@ A
 of
 .Pa /
 effectively disables the chroot.
+.It Fl P Ar pledge
+Restrict all spawned processes to the pledge
+.Ar pledge .
 .It Fl s Ar socket
 Create and bind to alternative local socket at
 .Ar socket .
diff --git usr.sbin/slowcgi/slowcgi.c usr.sbin/slowcgi/slowcgi.c
index a9a90b2db1f..16cfbd1b80a 100644
--- usr.sbin/slowcgi/slowcgi.c
+++ usr.sbin/slowcgi/slowcgi.c
@@ -275,6 +275,7 @@ main(int argc, char *argv[])
struct passwd   *pw;
struct stat  sb;
int  c, fd;
+   const char  *execpledge = NULL;
const char  *chrootpath = NULL;
const char  *slowcgi_user = SLOWCGI_USER;
 
@@ -303,6 +304,9 @@ main(int argc, char *argv[])
case 'p':
chrootpath = optarg;
break;
+   case 'P':
+   execpledge = optarg;
+   break;
case 's':
fcgi_socket = optarg;
break;
@@ -353,7 +357,7 @@ main(int argc, char *argv[])
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
lerr(1, "unable to revoke privs");
 
-   if (pledge("stdio rpath unix proc exec", NULL) == -1)
+   if (pledge("stdio rpath unix proc exec", execpledge) == -1)
lerr(1, "pledge");
 
SLIST_INIT(_proc.requests);



Re: Exec pledges

2017-10-08 Thread Ori Bernstein
This is my pledge(1). There are many like it, but this one is mine.
When directory pledges land, this should also get support for them.

Usage example:

pledge stdio echo hello world

More complicated, with enough pledges to run awk:

pledge "stdio rpath wpath cpath proc exec prot_exec" \
awk 'BEGIN {print "hi"}'




diff --git usr.bin/Makefile usr.bin/Makefile
index f428c790fe7..d4c506bc918 100644
--- usr.bin/Makefile
+++ usr.bin/Makefile
@@ -18,7 +18,7 @@ SUBDIR= apply arch at aucat audioctl awk banner \
midiplay mixerctl mkdep mklocale mktemp nc netstat \
newsyslog \
nfsstat nice nm nl nohup openssl pagesize passwd paste patch pctr \
-   pkg-config pkill \
+   pkg-config pkill pledge \
pr printenv printf quota radioctl rcs rdist rdistd \
readlink renice rev rpcgen rpcinfo rs rup rusers rwall \
sdiff script sed sendbug shar showmount signify skey \
diff --git usr.bin/pledge/Makefile usr.bin/pledge/Makefile
new file mode 100644
index 000..cdcccf1af61
--- /dev/null
+++ usr.bin/pledge/Makefile
@@ -0,0 +1,6 @@
+#  $OpenBSD$
+
+PROG=  pledge
+CFLAGS+= -Wall -Werror
+
+.include 
diff --git usr.bin/pledge/pledge.1 usr.bin/pledge/pledge.1
new file mode 100644
index 000..e049277fdff
--- /dev/null
+++ usr.bin/pledge/pledge.1
@@ -0,0 +1,44 @@
+.\" $OpenBSD$
+.\"
+.\"Copyright (c) 2017 Ori Bernstein 
+.\"
+.\"Permission to use, copy, modify, and 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.
+.Dd $Mdocdate: September 4 2017 $
+.Dt PLEDGE 1
+.Os
+.Sh NAME
+.Nm pledge
+.Nd execute commands under a pledge promise
+.Sh SYNOPSIS
+.Nm pledge
+.Ar promise
+.Ar command...
+.Sh DESCRIPTION
+The
+.Nm pledge
+utility executes the given command with the provided pledge
+restrictions. The first argument specifies the
+.Ar promise
+that the
+.Ar command
+will be run under.
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Ox 6.2 .
+.Sh BUGS
+This program does not support directory pledges.
+.Sh AUTHORS
+.An Ori Bernstein Aq Mt o...@eigenstate.org
+
diff --git usr.bin/pledge/pledge.c usr.bin/pledge/pledge.c
new file mode 100644
index 000..0431df7c7de
--- /dev/null
+++ usr.bin/pledge/pledge.c
@@ -0,0 +1,15 @@
+#include 
+#include 
+#include 
+
+int
+main(int argc, char **argv)
+{
+   if (argc < 2)
+   errx(1, "%s pledge cmd...\n", argv[0]);
+   if (pledge("stdio exec", argv[1]) == -1)
+   err(1, "pledge");
+   if (execvp(argv[2], [2]) == -1)
+   err(1, "exec");
+   return 0;
+}



Exec pledges

2017-10-08 Thread Ori Bernstein
I wrote some patches to allow pledging across execs.
Currently, the exec pledge passes down the process tree.

The initial version simply inherited the current pledge when
execing with the `pledge("rexec")` promise, but after
discussing with Theo at EuroBSD, a better design was
suggested.  Because directory pledges are going to be their
own system call, we can repurpose the second argument of
pledge as the "exec pledge".

My use is for sandboxing a bad idea, where arbitrary users can
submit code to a sandbox for my pet language, sitting on my
website, which gets compiled and run.  In the base system, it
seems like many programs with pledge("exec") invoke arbitrary
binaries on behalf of the user, but there are others (eg, pax)
that expect specfic behavior from what they exec.

This also could have broader uses -- for example, pledging
entire shell scripts. It also helps mitigate the case where an
attacker might fool us into exec()ing the wrong binary.

This is split into four patches:

- Adding kernel+libc support and docs. This changes the
  signature of pledge, but because everything calls
  plege("promises", NULL), things keep working.

- Add a pledge(1) binary + docs. This allows enforcing
  arbitrary pledges for a process tree. The minimal pledge for
  dynamically linked executables is a bit broad ("stdio rpath
  prot_exec"), due to ld.so, but this is still usefully
  restrictive. For statically linked executables, we do even
  better.  'pledge stdio echo hi' works just fine.

- The third patch adds the ability to pledge programs running
  under slowcgi.

- The fourth patch exec-pledges pax. I'm not sure I got the
  pledges right, so more careful review would be appreciated.
  I grabbed the pledges from compress, which seem to be a
  superset of the bzip2 pledges.

Regress tests would be good to add. I haven't done the work
yet, but it's mostly a matter of figuring out how to arrange
the makefiles to produce a binary that can be exec'ed. The
examples I see all seem to just produce one regress binary.

In an appropriate turn of events, this patch was written
while sitting in a capsicum talk at EuroBSD.



diff --git include/unistd.h include/unistd.h
index ffec1538f44..1faf2543f3d 100644
--- include/unistd.h
+++ include/unistd.h
@@ -522,7 +522,7 @@ int  strtofflags(char **, u_int32_t *, u_int32_t *);
 int swapctl(int cmd, const void *arg, int misc);
 int syscall(int, ...);
 int getentropy(void *, size_t);
-int pledge(const char *, const char **);
+int pledge(const char *, const char *);
 pid_t   __tfork_thread(const struct __tfork *, size_t, void (*)(void *),
void *);
 #endif /* __BSD_VISIBLE */
diff --git lib/libc/sys/pledge.2 lib/libc/sys/pledge.2
index 89884352500..9bfedc3d14b 100644
--- lib/libc/sys/pledge.2
+++ lib/libc/sys/pledge.2
@@ -23,7 +23,7 @@
 .Sh SYNOPSIS
 .In unistd.h
 .Ft int
-.Fn pledge "const char *promises" "const char *paths[]"
+.Fn pledge "const char *promises" "const char *execpromises"
 .Sh DESCRIPTION
 The current process is forced into a restricted-service operating mode.
 A few subsets are available, roughly described as computation, memory
@@ -31,9 +31,16 @@ management, read-write operations on file descriptors, 
opening of files,
 networking.
 In general, these modes were selected by studying the operation
 of many programs using libc and other such interfaces, and setting
-.Ar promises
-or
-.Ar paths .
+.Ar promises.
+.Pp
+Specifying
+.Ar execpromises
+allow the programmer to set the default pledge set for all future
+processes process that are execed. This is allows for inheriting
+.Fn fork
+and
+.Fn exec
+calls.
 .Pp
 Use of
 .Fn pledge
@@ -70,7 +77,7 @@ Passing
 to
 .Fa promises
 or
-.Fa paths
+.Fa execpromises
 specifies to not change the current value.
 .Pp
 Some system calls, when allowed, have restrictions applied to them:
@@ -143,9 +150,7 @@ support:
 system sensor readings.
 .Pp
 .It Fn pledge
-Can only reduce permissions; can only set a list of
-.Pa paths
-once.
+Can only reduce permissions.
 .El
 .Pp
 The
@@ -467,8 +472,8 @@ Allows a process to call
 Coupled with the
 .Va proc
 promise, this allows a process to fork and execute another program.
-The new program starts running without pledge active and hopefully
-makes a new
+The new program starts running with the requested exec pledges active
+and hopefully makes a new
 .Fn pledge .
 .It Va prot_exec
 Allows the use of
@@ -556,10 +561,6 @@ Allow
 operation for statistics collection from a bpf device.
 .El
 .Pp
-A whitelist of permitted paths may be provided in
-.Ar paths .
-All other paths will return
-.Er ENOENT .
 At least one promise is required to be pledged in order to activate a 
whitelist.
 .Sh RETURN VALUES
 .Rv -std
diff --git regress/sys/kern/pledge/generic/manager.c 
regress/sys/kern/pledge/generic/manager.c
index 451a3ecc088..e6af6b3d69e 100644
--- regress/sys/ke