>Synopsis: pledge allows /dev/null to be any file type >Category: kernel >Environment: System : OpenBSD 7.2 Details : OpenBSD 7.2 (GENERIC.MP) #2: Thu Nov 24 23:53:03 MST 2022 r...@syspatch-72-arm64.openbsd.org:/usr/src/sys/arch/arm64/compile/GENERIC.MP
Architecture: OpenBSD.arm64 Machine : arm64 >Description: I was testing pledge on a 7.2 system and as a test opened /dev/null. I was astonished that it didn't abort. OK perhaps it needs to do that but doesn't it work better if /dev/null is major/minor (2,2) device? I have a ktrace for you to show what I mean. >How-To-Repeat: spica# mkdir dev mkdir: dev: File exists spica# touch dev/null spica# ktrace -i ./testprog spica# ls -l dev/null -rw-r--r-- 1 root pjp 5 Mar 19 22:51 dev/null spica# cat dev/null test spica# The ktrace I'm gonna edit it to show only the juicy parts: 13252 testprog CALL chroot(0x995cc0ea640) 13252 testprog NAMI "/home/pjp" 13252 testprog RET chroot 0 13252 testprog CALL kbind(0x7f7fffff95b8,24,0xd10fcc1b312a79c0) 13252 testprog RET kbind 0 13252 testprog CALL chdir(0x995cc0ea64a) 13252 testprog NAMI "/" 13252 testprog RET chdir 0 13252 testprog CALL kbind(0x7f7fffff95b8,24,0xd10fcc1b312a79c0) 13252 testprog RET kbind 0 13252 testprog CALL pledge(0x995cc0ea652,0) 13252 testprog STRU promise="stdio" 13252 testprog RET pledge 0 13252 testprog CALL kbind(0x7f7fffff95b8,24,0xd10fcc1b312a79c0) 13252 testprog RET kbind 0 13252 testprog CALL open(0x995cc0ea658,0x1<O_WRONLY>) 13252 testprog NAMI "/dev/null" 13252 testprog RET open 4 13252 testprog CALL kbind(0x7f7fffff95b8,24,0xd10fcc1b312a79c0) 13252 testprog RET kbind 0 13252 testprog CALL write(4,0x995cc0ea64c,0x5) 13252 testprog GIO fd 4 wrote 5 bytes "test So writing to a file called {CHROOT}/dev/null is allowed on stdio pledge. This is very suboptimal to me. Can't it perform a check for major 2, minor 2? spica# ls -l /dev/null crw-rw-rw- 1 root wheel 2, 2 Mar 19 10:14 /dev/null >Fix: >From github I got this for the HEAD of CVS from: https://github.com/openbsd/src/blob/master/sys/kern/kern_pledge.c -----> case SYS_open: /* daemon(3) or other such functions */ if ((ni->ni_pledge & ~(PLEDGE_RPATH | PLEDGE_WPATH)) == 0 && strcmp(path, "/dev/null") == 0) { ni->ni_cnd.cn_flags |= BYPASSUNVEIL; return (0); } <------ I figure that's the code for this, partially. But someone else would surely know better. And has surely a better fix on hand? dmesg: see previous reports.