You could imagine combining seccomp-bpf with some other system that reads the arguments after they've been copied to kernelspace, which is basically Landlock's approach https://lwn.net/Articles/698226/. But I've been personally waiting for something like this since 2011 or so when people were saying seccomp mode 2 should use ftrace, and Landlock itself has been in review (slash argument) for two years. An approach like gVisor works today.
This is something that is being worked on (separately but similar to Landlock) in the form of seccomp syscall emulation (I don't remember the actual name of the patchset at the moment but it was proposed a month ago I think). However after talking to some seccomp folks I was told that in theory eBPF maps could be used for this purpose (though I'm not really convinced to be honest).
The real downside of ptrace is that you cannot filter which syscalls you're interested in -- so you pay the price of tracing for every syscall. seccomp doesn't have this problem.
if syscall == SYS_open:
if flags == O_RDONLY:
return (SECCOMP_RET_TRACE, 0)
else:
return (SECCOMP_RET_ERRNO, EPERM)
else if syscall in (SYS_read, SYS_write, ...):
return (SECCOMP_RET_ALLOW, 0)
else:
return (SECCOMP_RET_ERRNO, ENOSYS)
and it would be much much faster than tracing every system call, since most programs call open() rarely and read() and write() very often.That said, the ptracer's job here is kind of hard, because the kernel still gets an untrusted userspace pointer, and another thread, another process, etc. can modify that memory in between the ptracer okaying it and the kernel getting to it. (See "Argument races" in Tal Garfinkel's 2003 "Traps and Pitfalls" paper.) So you either want the filtering to happen in the kernel after it's been copied to kernelspace (which is Landlock's approach), or do the open from a trusted process and send the fd over (which is I think gVisor's approach).
That's not even the least of it, it's impossible to implement the ratcheting down semantics of pledge() using seccomp-bpf. For example, an initial pledge("stdio rpath") may be later reduced to pledge("stdio").
"Subsequent calls to pledge can reduce the abilities further, but abilities can never be regained."https://man.openbsd.org/pledge
See also execpromises, which addresses your issue.
From:
https://godoc.org/github.com/google/gvisor/pkg/sentry/platfo...