Confusing output (no error message) when tty is not pledged but program queries ioctl TIOCGWINSZ
rsms opened this issue · comments
Busybox programs queries TIOCGWINSZ on startup, meaning benign commands like seq
needs to pledge "tty". Failing to do so causes pledge to "silently" fail, printing "Bad system call" (no error messages reported.)
$ pledge -p "stdio" /bin/seq 1
Bad system call
$ pledge -p "stdio tty" /bin/seq 1
1
Original issue:
On a barebones musl (Linux 6.5.8)
$ pledge -p "stdio" /bin/date
Bad system call
$ pledge -p "stdio exec" /bin/date
Mon Apr 29 22:44:12 UTC 2024
The culprit seems to be __pledge_mode & PLEDGE_STDERR_LOGGING
Line 841 in 8693ebe
since if I pass -q
to pledge, exec works as expected:
$ pledge -q -p "stdio" /bin/date
Mon Apr 29 22:45:30 UTC 2024
Additionally, passing -k
to pledge (sets __pledge_mode = PLEDGE_PENALTY_KILL_PROCESS) also results in "Bad system call", even with -q
:
$ pledge -k -p "stdio" /bin/date
Bad system call
$ pledge -k -q -p "stdio" /bin/date
Bad system call
If I disable "implicit exec" by commenting out these lines...
Lines 838 to 843 in 8693ebe
... execv fails with the expected "Operation not permitted" error message:
$ pledge -p "stdio" /bin/date
/bin/date: execve failed: Operation not permitted
The least messy fix I've come up with is to always include a SECCOMP_RET_ERRNO filter:
Edit: I realize now that this patch breaks stuff (as it returns early)
--- a/libc/calls/pledge-linux.c 2023-11-08 18:18:17.000000000 +0000
+++ b/libc/calls/pledge-linux.c 2024-04-29 23:10:44.057225745 +0000
@@ -2129,6 +2129,9 @@
}
}
+ sf[0].k = SECCOMP_RET_ERRNO;
+ AppendFilter(&f, PLEDGE(sf));
+
// now determine what we'll do on sandbox violations
if (mode & PLEDGE_STDERR_LOGGING) {
// trapping mode
(Note: /bin/date in this example is a static executable, so sandbox.so is not involved)
Linux 6.5.8 is built with:
CONFIG_HAVE_ARCH_SECCOMP=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
Pledging tty and rpath makes it work as well:
$ pledge -p "stdio" /bin/date
Bad system call
$ pledge -p "stdio rpath" /bin/date
Bad system call
$ pledge -p "stdio tty" /bin/date
Bad system call
$ pledge -p "stdio rpath tty" /bin/date
Mon Apr 29 23:36:15 UTC 2024
/bin/date is busybox — perhaps busybox reads the file system and calls e.g. SYS_ioctl TIOCGWINSZ on every invocation..?
Edit: Ah, yes indeed it reads /etc/localtime and queries TIOCGWINSZ:
$ strace /bin/date
execve("/bin/date", ["/bin/date"], 0xffffe81ab850 /* 18 vars */) = 0
set_tid_address(0x3b4a50) = 29898
getuid() = 0
openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=114, ...}) = 0
mmap(NULL, 114, PROT_READ, MAP_SHARED, 3, 0) = 0xffff89e4b000
close(3) = 0
ioctl(1, TIOCGWINSZ, {ws_row=55, ws_col=100, ws_xpixel=0, ws_ypixel=0}) = 0
writev(1, [{iov_base="Mon Apr 29 23:37:55 UTC 2024", iov_len=28}, {iov_base="\n", iov_len=1}], 2Mon Apr 29 23:37:55 UTC 2024
) = 29
exit_group(0) = ?
+++ exited with 0 +++