Greetings tech@,

First off, a real heartfelt thanks to you for OpenBSD,
and props to those who already scouted some of this
ground in 2015 (and, presumably, since).  I had noted
some discussion threads and blogs, but can't find them
after ten minutes now (forgive me, but just the text notes
for this project is more than half a million characters).

TL;DR => skip to @@1

Cave!  I am not a systems programmer. (until now)
Also, this code is very preliminary and not a pleasure to
look at; sorry.  I feel it's time to share what I've got,
take a breather, maybe get some feedback.

The license is still "for private review", but will
be BSD licensed soon (say two weeks at the most).

Finally, there are no patches b/c ... it's too soon...
If there's seriously demand for a kernel patch,
just a clean pledgepid(2) patch, I can provide one
within a day, that's no problem, I just didn't get
there today and this is my personal deadline to post.

I am prepared to be told this is unsecure, but I've tried
to be mindful of the pledge(2) security philosophy, so hopefully
there will be something salvagable... *shrug*

More chatty stuff farther below. ;)

@@1

pledge(1) synopsis:
  https://fremissant.net/pledge/20190505-01/pledge-synopsis.png

usage: (common options [-123cdhks] are also accepted by most invocations)
  pledge [-At] [[-p] promises] [-e execproms] [-v path permiss] command
  unveil [-At] path permiss [-p promises] [-e execproms] command
  pledge [-a] [{pid|name}]  |  pledge -q[a] {pid|name} ...
  pledge -P[a] s-promises [-e s-execproms] {pid|name} ...
  pledge -g [-Os] [-x slowdown] command
  command

A tarball:
  https://fremissant.net/pledge/20190505-01/pledge-20190505-01.tar
SHA256 (pledge-20190505-01.tar) =
 f7305eff297fac1f19b6d296deb9cf83e336de046956b3e010f713a069a6a6c0
[Contains the manpages, souce project including build script
and tests, the pledgepid kernel code (not patch), ...]

Manpage links:
  https://fremissant.net/pledge/20190505-01/pledge.1
  https://fremissant.net/pledge/20190505-01/pledge.2
  https://fremissant.net/pledge/20190505-01/pledge.3
  https://fremissant.net/pledge/20190505-01/pledge.5
  https://fremissant.net/pledge/20190505-01/plenge.6 [sic]
[I really don't like the mandoc HTML appearance, so
please use your favourite mdoc pager.]

Capabilities:
 //  - Wrap a command in a pledge and/or unveiling
 //  - Query the pledge/unveiling of existing processes
 //  - Place a running process under pledge/unveiling
 //  - Modify pledge/unveiling of existing processes
 //  - Play "plenge" and help harden OpenBSD and your userland!...
 //
 // See also pledge(2356).

Benefits from new syscall, pledgepid(2), which handles both
querying and pledging:

331  STD  { int sys_pledgepid(pid_t pid, const char *promises, \
            const void *execpromises); }

[Actually there are two versions, the other taking more arguments:
undecided which is best, or whether to keep both; or perhaps to
have some general, adaptable syscall comparable to ptrace/ktrace,
which handles all pledge functionality?]

pledge(1) can run without pledgepid(2) in the kernel, but
it becomes a mere wrapper for pledge(2)+execve(2) and, while
still useful, is quite limited in comparison.

Exmples below.

------------------------------------------

Skip to examples => @@2

There was some early work towards a pledge(1) back in 2015 when
pledge(2) work was peaking, and I know there was a final slide in
Bob Beck's presentation on pledge(2) a couple years back sketching
the idea at Theo's insistence. :) Reasons it hasn't emerged might
include:
 - most apps need a settling period before some promises can be dropped
 - the overlay is stuck with initial execpromises equal to promises, and
   must contain "stdio rpath" [don't believe me?], so not fully general
 - forking, and pledging each process minimally, is a useful pattern
   which pledge(2) rewards, but which is incompatible with a pledge(1)
   which pledges the overlay process before it has had a chance to fork
    - condemning all future forks to inherit those promises or a subset
 - and now that all of base is pledged optimally and directly via
   pledge(2), any use of pledge(1) would seem relegated to ports.
 - everyone is more tactful than I?...

@@2

Nevertheless, a pledge(1) which simply exec's a command
while under pledge(2) is better than nothing, and I've been
using it to pledge the Links browser [awesome browser! goodbye
chromium and firefox except in rare case of need for JS]:

# pledge rpath,stdio,cpath,tty,dns,inet,unix,proc links -g https://...

(Plus need "wpath" to save downloads.)

It's like everything came together the last few days.  So I could
now pledge this tighter, after it starts...  Not even tried; working
on the -A option mainly......

I don't have a perfect solution to the limitations, but what there is
might be of interest.  What you can do depends whether you have the
pledgepid(2) syscall.  If you don't have it, we'll call it "pledge-puny",
and the tool in its current incarnation simply "pledge".

# cat stdioer.c
# #include <stdio.h> main(){ printf("...stdioing...\n"); usleep(1000000); }
# cc stdioer.c -o stdioer
# pledge-puny "stdio rpath" stdioer    # wrapper for pledge(2)+execve(2)
... stdioing ...
# pledge stdioer                       # (queries newest; use -a for all)
66227 stdioer p=rpath,stdio ep=rpath,stdio
# pledge                               # system summary
    1 /sbin/init                     p=  OPEN             ep=  OPEN            
10274 /sbin/mount_mf...00 swap /tmp  p=  OPEN             ep=  OPEN            
59675 /sbin/mount_mf...work/ramdisk  p=  OPEN             ep=  OPEN            
29316 slaacd                         p=0x..........1..1.8 ep=  OPEN            
13116 /sbin/slaacd                   p=0x.......8.......8 ep=  OPEN            
44490 slaacd                         p=0x...............8 ep=  OPEN            
 7752 /usr/sbin/syslogd              p=0x...........4.148 ep=  OPEN            
36209 syslogd                        p=0x...........A122F ep=  OPEN            
92098 pflogd                         p=  OPEN             ep=  OPEN            
18531 pflogd                         p=0x...........4...8 ep=  OPEN            
71312 /usr/sbin/ntpd                 p=0x...........83249 ep=  OPEN            
 ...
77783 sct -d                         p=0x...........811.F ep=0x........8..B5BEF
 ...

Note that with pledge-puny, it is impossible to pledge a command with
less than "stdio rpath".  Both promises are absolutely needed to
effect an execve(2) under pledge.  (I think it's the loader.)  So,
in particular, such a pledge(1) could not restrict the execee to pure
computation, even if that's all the overlay does.

You can pledge the unpledged; and shed promises from the pledged:

# pledge stdioer                       # again
66227 stdioer p=rpath,stdio ep=rpath,stdio
# pledge -P -rpath -e pure stdioer     # not pledge-puny!
# pledge stdioer                       # again
66227 stdioer p=stdio ep=(pure)

May warmest regards,
Andy.

P.S. I'd wanted to plan my first post with care, but all my cares
have been more than occupied with the code...  So much so that
I will soon need to put this down for a while, other stuff
is clamouring for attention.  This is the first fruits of my
move to OpenBSD (on my birthday, Jan. 29 :), after years of linux,
back to a *real UNIX* and .... it's like a homecoming.  (My first
*nix experience was SunOS around 1990, and cut my teeth there
and in Solaris for a decade.)

A combination of finally catching up on the Snowden thing, plus systemd,
finally brought me over.  Am I being too chatty?  I probably need
some sleep; may the universe not send me dreams of code I can't save...

Reply via email to