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...
