Florian Weimer of Red Hat reports: the sudoers manual page says this: EXEC and NOEXEC If sudo has been compiled with noexec support and the underly‐ ing operating system supports it, the NOEXEC tag can be used to prevent a dynamically-linked executable from running further commands itself. In the following example, user aaron may run /usr/bin/more and /usr/bin/vi but shell escapes will be disabled. aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi And: To enable noexec for a command, use the NOEXEC tag as documented in the User Specification section above. Here is that example again: aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi This allows user aaron to run /usr/bin/more and /usr/bin/vi with noexec enabled. This will prevent those two commands from executing other commands (such as a shell). If you are unsure whether or not your system is capable of supporting noexec you can always just try it out and check whether shell escapes work when noexec is enabled. However, the filtering DSO does not intercept all glibc functions which allow to spawn a shell. At least popen, system, and wordexp are missing: Show quoted text 0000000000000c80 T execl 0000000000000cc0 T _execl 0000000000000d00 T __execl 0000000000000d40 T execle 0000000000000d80 T _execle 0000000000000dc0 T __execle 0000000000000e00 T execlp 0000000000000e40 T _execlp 0000000000000e80 T __execlp 0000000000000ec0 T exect 0000000000000f00 T _exect 0000000000000f40 T __exect 0000000000000f80 T execv 0000000000000fc0 T _execv 0000000000001000 T __execv 00000000000011c0 T execve 0000000000001200 T _execve 0000000000001240 T __execve 0000000000001040 T execvp 0000000000001080 T _execvp 00000000000010c0 T __execvp 0000000000001100 T execvP 0000000000001140 T _execvP 0000000000001180 T __execvP 0000000000001280 T execvpe 00000000000012c0 T _execvpe 0000000000001300 T __execvpe 0000000000001340 T fexecve 0000000000001380 T _fexecve 00000000000013c0 T __fexecve 0000000000001480 T __posix_spawn 0000000000001440 T _posix_spawn 0000000000001400 T posix_spawn 0000000000001540 T __posix_spawnp 0000000000001500 T _posix_spawnp 00000000000014c0 T posix_spawnp The source file src/sudo_noexec.c contains this comment: /* * Dummy versions of the execve() family of syscalls. We don't need * to stub out all of them, just the ones that correspond to actual * system calls (which varies by OS). Note that it is still possible * to access the real syscalls via the syscall() interface but very * few programs actually do that. */ This is wrong. Interposing execve does not override internal calls to execve within glibc. The right fix is to set a seccomp filter which blocks execve in the DSO (after enabling PR_SET_NO_NEW_PRIVS), rather than attempting to play catch-up with glibc.
Acknowledgments: Name: Florian Weimer (Red Hat)
Apparently upstream is aware of the problem and addressed system() and popen() cases about a year ago: https://www.sudo.ws/devel.html#1.8.15rc1 https://www.sudo.ws/repos/sudo/rev/58a5c06b5257 https://www.sudo.ws/repos/sudo/rev/a826cd7787e9
(In reply to Tomas Hoger from comment #2) > Apparently upstream is aware of the problem and addressed system() and > popen() cases about a year ago: > > https://www.sudo.ws/devel.html#1.8.15rc1 > https://www.sudo.ws/repos/sudo/rev/58a5c06b5257 > https://www.sudo.ws/repos/sudo/rev/a826cd7787e9 Ahh, maybe that's why I was vaguely familiar with this issue. True blocking still needs a seccomp filter, though.
The sudo version in Red Hat Enterprise Linux 5 also lacks this commit: https://www.sudo.ws/repos/sudo/rev/cbaa1d4b0f8a Blocking wrappers for posix_spawn() and posix_spawnp() are relevant. exect() seems BSD-specific API, and execvpe() was only added in glibc 2.11, while Red Hat Enterprise Linux 5 includes glibc 2.5.
(In reply to Kurt Seifried from comment #0) > The right fix is to set a seccomp filter which blocks execve in the DSO > (after enabling PR_SET_NO_NEW_PRIVS), rather than attempting to play > catch-up with glibc. As far as I can see, such seccomp approach would only be viable on Red Hat Enterprise Linux 7 or later. I'm also unsure if sudo upstream would be willing to write the code. Do you or sudo maintainer have capacity to implement this and get is merged upstream?
(In reply to Tomas Hoger from comment #5) > (In reply to Kurt Seifried from comment #0) > > The right fix is to set a seccomp filter which blocks execve in the DSO > > (after enabling PR_SET_NO_NEW_PRIVS), rather than attempting to play > > catch-up with glibc. > > As far as I can see, such seccomp approach would only be viable on Red Hat > Enterprise Linux 7 or later. I'm also unsure if sudo upstream would be > willing to write the code. Do you or sudo maintainer have capacity to > implement this and get is merged upstream? A while back I wrote: https://github.com/fweimer/noexecve/blob/master/noexecve.c It's not 100% complete because it does not deal with multi-arch system calls. On x86_64, a program could still evade this by jumping to short mode and doing the i386 syscalls (which have different numbers), or call the x32 syscalls. In most cases, this will need some sort of code execution exploit in the target process because the process will not expose this sort of capability to the end user.
Would this also need other tweaks for other non-x86 architectures? Would use of libseccomp be recommended to hide platform specific details?
(In reply to Tomas Hoger from comment #8) > Would this also need other tweaks for other non-x86 architectures? Other architectures may have different forms of compatibility system calls, yes. > Would use of libseccomp be recommended to hide platform specific details? I don't know if it handles multi-arch system calls in the way needed. I have asked Paul Moore.
The following changes were applied upstream for inclusion in 1.8.18p1: * Wrapper for wordexp() was added to sudo_noexec.so which forces the use of WRDE_NOCMD flag in wordexp(). https://www.sudo.ws/repos/sudo/rev/e7d09243e51b https://www.sudo.ws/repos/sudo/rev/7b8357b0a358 https://www.sudo.ws/repos/sudo/rev/167a518d8129 NEWS file entry: * When sudo_noexec.so is used, the WRDE_NOCMD flag is now added if the wordexp() function is called. This prevents commands from being run via wordexp() without disabling it entirely. * seccomp support was added to sudo_noexec.so. https://www.sudo.ws/repos/sudo/rev/59d76bdc0f0c https://www.sudo.ws/repos/sudo/rev/5d88d7cda853 NEWS file entry: * On Linux systems, sudo_noexec.so now uses a seccomp filter to disable execute access if the kernel supports seccomp. This is more robust than the traditional method of using stub functions that return an error.
As system()/popen() and wordexp() were fixed in different versions, the wordexp() case will be tracked under separate CVE-2016-7076 - see bug 1384982.
Public now via upstream advisory. External References: https://www.sudo.ws/alerts/noexec_bypass.html
This issue has been addressed in the following products: Red Hat Enterprise Linux 6 Red Hat Enterprise Linux 7 Via RHSA-2016:2872 https://rhn.redhat.com/errata/RHSA-2016-2872.html