On 2019-05-07, Aleksa Sarai wrote: > On 2019-05-06, Jann Horn wrote: > > On Mon, May 6, 2019 at 6:56 PM Aleksa Sarai wrote: > > > The need to be able to scope path resolution of interpreters became > > > clear with one of the possible vectors used in CVE-2019-5736 (which > > > most major container runtimes were vulnerable to). > > > > > > Naively, it might seem that openat(2) -- which supports path scoping -- > > > can be combined with execveat(AT_EMPTY_PATH) to trivially scope the > > > binary being executed. Unfortunately, a "bad binary" (usually a symlink) > > > could be written as a #!-style script with the symlink target as the > > > interpreter -- which would be completely missed by just scoping the > > > openat(2). An example of this being exploitable is CVE-2019-5736. > > > > > > In order to get around this, we need to pass down to each binfmt_* > > > implementation the scoping flags requested in execveat(2). In order to > > > maintain backwards-compatibility we only pass the scoping AT_* flags. > > > > > > To avoid breaking userspace (in the exceptionally rare cases where you > > > have #!-scripts with a relative path being execveat(2)-ed with dfd != > > > AT_FDCWD), we only pass dfd down to binfmt_* if any of our new flags are > > > set in execveat(2). > > > > This seems extremely dangerous. I like the overall series, but not this patch. > > > > > @@ -1762,6 +1774,12 @@ static int __do_execve_file(int fd, struct filename *filename, > > > > > > sched_exec(); > > > > > > + bprm->flags = flags & (AT_XDEV | AT_NO_MAGICLINKS | AT_NO_SYMLINKS | > > > + AT_THIS_ROOT); > > [...] > > > +#define AT_THIS_ROOT 0x100000 /* - Scope ".." resolution to dirfd (like chroot(2)). */ > > > > So now what happens if there is a setuid root ELF binary with program > > interpreter "/lib64/ld-linux-x86-64.so.2" (like /bin/su), and an > > unprivileged user runs it with execveat(..., AT_THIS_ROOT)? Is that > > going to let the unprivileged user decide which interpreter the > > setuid-root process should use? From a high-level perspective, opening > > the interpreter should be controlled by the program that is being > > loaded, not by the program that invoked it. > > I went a bit nuts with openat_exec(), and I did end up adding it to the > ELF interpreter lookup (and you're completely right that this is a bad > idea -- I will drop it from this patch if it's included in the next > series). > > The proposed solutions you give below are much nicer than this patch so > I can drop it and work on fixing those issues separately. Another possible solution would be to only allow (for instance) AT_NO_MAGICLINKS for execveat(2). That way you cannot scope the resolution but you can block the most concerning cases -- those involving /proc-related access. I've posted a v7 with this patch dropped (because we can always add AT_* flags later in time), but I think having at least NO_MAGICLINKS would be useful. -- Aleksa Sarai Senior Software Engineer (Containers) SUSE Linux GmbH