Re: [PATCH v6 5/6] binfmt_*: scope path resolution of interpreters
From: Aleksa Sarai <hidden>
Date: 2019-05-08 00:55:35
Also in:
linux-arch, linux-fsdevel, lkml
On 2019-05-07, Aleksa Sarai [off-list ref] wrote:
On 2019-05-06, Jann Horn [off-list ref] wrote:quoted
On Mon, May 6, 2019 at 6:56 PM Aleksa Sarai [off-list ref] wrote:quoted
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.quoted
@@ -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);[...]quoted
+#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 <https://www.cyphar.com/>
Attachments
- signature.asc [application/pgp-signature] 833 bytes