I don't think the post is wrong, but I think it's overly pessimistic. Is it the best API out there? No. Is it "unsafe at any speed"? Also no - in fact, the author doesn't really talk about safety at all? My belief is that you're better off using it than not using it: it's a pretty robust, lightweight security boundary.
Yes, there are some related syscalls, such as open() / openat(), and every now and then, some new version of libc may start calling one when you think it should be using the other. But I don't see how that supports the thesis of the subsystem being unsafe. It's a hurdle for package maintainers, perhaps?
"And that’s just for the most trivial of examples where you have some unsafe code (e.g. a parser) that takes input on one fd and gives output on another." - the list of syscalls listed in the article is far longer than what you need for a parser. It's a list for a network service. And I think that overlooks one of the key principles you should be aiming with this type of static-policy sandboxing: you want to isolate each functional block. For example, a single policy that "fits" the entire SSH server cradle-to-grave is more or less useless because it needs access to everything. But if you split out networking handling, protocol parsing, and session management into separate processes, you can apply more sensible policies to each.
Even with full control of the process, what could you possibly do after it runs pledge("stdio", "")? Print profanities to the user? Exit with the wrong exit code? Yeah, but that’s about it.
I think this misses a critical point about pledge. Pledge is called by the program at a particular time typically after some initial state is built up. This can involve sockets or files other than stdout/stderr being opened. The stdio pledge still allows the program to read and write to those file descriptors.
vmd(8) is one such program where the virtio block device emulation IIRC drops to just a pledge of “stdio”, but it can still communicate to the parent process via unix socket, read/write data to the backing disk image file(s), AND print profanities to the user on stdout/stderr!
I'm commenting on what I consider an incorrect way to explain what a pledge of "stdio" OpenBSD means in practice as someone that's used pledge in programs. One cannot just view a single line calling pledge(2) and setting "stdio" and know the actual capabilities of the program. It reduces the space of what is possible, but you can't infer anything concrete without knowing the state of the program at that point in time.
lcamtuf | 22 hours ago
I don't think the post is wrong, but I think it's overly pessimistic. Is it the best API out there? No. Is it "unsafe at any speed"? Also no - in fact, the author doesn't really talk about safety at all? My belief is that you're better off using it than not using it: it's a pretty robust, lightweight security boundary.
Yes, there are some related syscalls, such as open() / openat(), and every now and then, some new version of libc may start calling one when you think it should be using the other. But I don't see how that supports the thesis of the subsystem being unsafe. It's a hurdle for package maintainers, perhaps?
"And that’s just for the most trivial of examples where you have some unsafe code (e.g. a parser) that takes input on one fd and gives output on another." - the list of syscalls listed in the article is far longer than what you need for a parser. It's a list for a network service. And I think that overlooks one of the key principles you should be aiming with this type of static-policy sandboxing: you want to isolate each functional block. For example, a single policy that "fits" the entire SSH server cradle-to-grave is more or less useless because it needs access to everything. But if you split out networking handling, protocol parsing, and session management into separate processes, you can apply more sensible policies to each.
jmtd | 23 hours ago
Well written (as is the linked follow up) and quite depressing.
mccd | 22 hours ago
Landlock is a really great alternative to unveil today. Unfortunately it cannot filter certain syscalls.
voutilad | 7 hours ago
I think this misses a critical point about pledge. Pledge is called by the program at a particular time typically after some initial state is built up. This can involve sockets or files other than stdout/stderr being opened. The stdio pledge still allows the program to read and write to those file descriptors.
vmd(8) is one such program where the virtio block device emulation IIRC drops to just a pledge of “stdio”, but it can still communicate to the parent process via unix socket, read/write data to the backing disk image file(s), AND print profanities to the user on stdout/stderr!
leameow | 7 hours ago
In some way, couldn't you just allow file syscall and deny
opentype of call with seccomp to get a similar behavior?voutilad | 6 hours ago
Maybe? I'm not an expert on seccomp.
I'm commenting on what I consider an incorrect way to explain what a pledge of "stdio" OpenBSD means in practice as someone that's used pledge in programs. One cannot just view a single line calling pledge(2) and setting "stdio" and know the actual capabilities of the program. It reduces the space of what is possible, but you can't infer anything concrete without knowing the state of the program at that point in time.