Closed ikmckenz closed 8 months ago
The epoll_ctl
clue is misleading here, "Permission denied" is the human-readable message for EACCES
, not for EPERM
(compare the errno(3) man page).
The Permission denied
error is in fact coming from the execve
call:
[pid 10054] execve("/usr/bin/ffprobe", ["/usr/bin/ffprobe", "-print_format", "json", "-show_streams", "foo.mp3"], 0xc000114160 /* 41 vars */) = -1 EACCES (Permission denied)
ffprobe
depends on a lot of additional libraries, which you can query using ldd $(which ffprobe)
. These normally reside in /usr/lib
(but it is technically configurable; the man page ld.so(8)
goes into the more detail on the exact resolution of these. The most notable exception is probably that some systems have an additional lib64
directory to tell apart 32-bit and 64-bit libraries.)
If I add the following argument to the Landlock invocation, it starts working:
landlock.RODirs("/usr/lib"),
So while I can see that this resolves the issue, I have to admit that I'm slightly surprised that it is already execve
which returns EACCES
- that means that it's already the kernel which starts poking around in /usr/lib
. I have so far been under the impression that glibc's startup routines were responsible for mmaping the shared libraries... So I would have expected the error slightly later in the execution, during the start of the program, but you would have to put the same additional Landlock parameter either way... :)
P.S.: Don't forget to check the error that is returned by RestrictPaths()
. This can fail, for example if one of the passed file or directory paths does not exist. (If you want to ignore this error for individual paths that might or might not exist, you can use landlock.ROFiles("/usr/lib64").IgnoreIfMissing()
)
Awesome, thank you for the pointers, this resolves my issue. If you don't mind my asking: How did you discover that epoll_ctl
wasn't the source of the error, and the Permissions denied error was coming from execve
, and that library loading was the thing to look at? I ran into the exact same issue when trying to sandbox the same code on OpenBSD with simultaneous pledge and unveil, and the resolution was the same (add /usr/lib/ et. al. to the unveil command), but on OpenBSD it was obvious from ktrace
where the error was. Using strace
on Linux didn't show me the exact error.
A common mistake that I like to make is to forget the -f
flag for strace
. That one traces all child processes as well, which you need for tracing execve, because execve happens in the forked-off child.
Other than that I just had a vague memory that the error codes and their spelled-out human-readable forms are not exactly intuitive in this case... ;)
Thank you!
Trying to sandbox a Go wrapper that calls ffprobe, code looks something like this:
This always returns
Using strace, I see it fails with
epoll_ctl(4, EPOLL_CTL_ADD, 3, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, data={u32=1363365560, u64=139699469635256}}) = -1 EPERM (Operation not permitted)
Is this a limitation from Landlock? Or is this something from the Go implementation?