"Exec Shield", new Linux security feature
Quoted 10 lines
Ingo Molnar wrote:
Quoted 3 lines · Carl-Daniel Hailfinger
If my math is correct,
0x01000000is 16 MB boundary0x01003fffis outside the ASCII-armor.the ASCII-armor, more precisely, is between addresses
0x00000000and0x0100ffff. Ie. 16 MB + 64K. [in the remaining 64K the \0 character is in the second byte of the address.] So the0x01003fffaddress is still inside the ASCII-armor.
To be precise, the first addressible address is 0x01010101 (16M+64K+256+1). Rounding this to a page boundary produces the figure above.
Just as a reminder, the standard stack-smashing attack for non-executable stacks works by overwriting the current call frame's return address with
[entry address of interesting function, like system()] [dummy return address]
[char *argument]
[string pointed to by above argument]
When the current function returns, the CPU will return to the entry address of system() with the desired arguments on the stack. (This is trickier on architectures which put arguments in registers, so you have to find a "pop argument registers; return" sequence in the standard library and return to that first.)
The ASCII string is then passed to some "interesting" function which has interpreter powers and "executes" it without caring about the processor's idea of execute permission.
If this is done by passing an unexpectedly long input to strcpy() or gets(), then none of the arguments can have an embedded zero byte, except the final string.
The stack address is needed to arrange for the char *argument to point to the string. If the string is an executable path, some uncertainty can be resolved by using a path like:
/../../../../../../../../../../../../../../../../../bin/sh
Or, if you know the stack is 2-byte aligned (people aren't usually willing to put up with the performance hit for odd stack pointers even on architectures like x86 which can handle them), you can use
/./././././././././././././././././././././././././bin/sh
A pointer a little past the start of the string will still end up referencing /bin/sh.
An interesting question arises: is the number of useful interpreter functions (system, popen, exec*) sufficiently low that they could be removed from libc.so entirely and only staticly linked, so processes that didn't use them wouldn't even have them in their address space, and ones that did would have them at less predictible addresses?
Right now, I'm thinking only of functions that end up calling execve(); are there any other sufficiently powerful interpreters hiding in common system libraries? regexec()?
Quoted 9 lines · On Sat, 03 May 2003 13:19:52 -0000, [email protected] said:
An interesting question arises: is the number of useful interpreter functions (system, popen, exec*) sufficiently low that they could be removed from libc.so entirely and only staticly linked, so processes that didn't use them wouldn't even have them in their address space, and ones that did would have them at less predictible addresses?
Right now, I'm thinking only of functions that end up calling
execve(); are there any other sufficiently powerful interpreters hiding in common system libraries?regexec()?
This does absolutely nothing to stop an exploit from providing its own inline version of execve(). There's nothing in libc that a process can't do itself, inline.
A better bet is using an LSM module that prohibits exec() calls from any unauthorized combinations of running program/user/etc.
Quoted 12 lines · On Sat, 3 May 2003 [email protected] wrote:
Quoted 9 lines · On Sat, 03 May 2003 13:19:52 -0000, [email protected] said:
An interesting question arises: is the number of useful interpreter functions (system, popen, exec*) sufficiently low that they could be removed from libc.so entirely and only staticly linked, so processes that didn't use them wouldn't even have them in their address space, and ones that did would have them at less predictible addresses?
Right now, I'm thinking only of functions that end up calling
execve(); are there any other sufficiently powerful interpreters hiding in common system libraries?regexec()?
Quoted 6 lines
This does absolutely nothing to stop an exploit from providing its own inline version of
execve(). There's nothing in libc that a process can't do itself, inline.A better bet is using an LSM module that prohibits
exec()calls from any unauthorized combinations of running program/user/etc.
Is that practical? I can see how with some daemons it would definitely be useful to prohibit exec calls (maybe things like BIND don't need to exec anything).. but some daemons do need to exec. An SMTPD may need to exec() some helper processes (postfix for instance has a whole slew of helper programs it uses).. and things like sshd need to exec a shell, etc..
It's still a good idea though, since some daemons don't need to exec, ever. I guess this is one extra layer of protection. As Ingo said in his announcement, the more layers of protection you have, the better.. and the more difficult a cracker's job is.
-Calin
Quoted 27 lines · Calin A. Culianu
Quoted 12 lines · On Sat, 3 May 2003 [email protected] wrote:
Quoted 9 lines · On Sat, 03 May 2003 13:19:52 -0000, [email protected] said:
An interesting question arises: is the number of useful interpreter functions (system, popen, exec*) sufficiently low that they could be removed from libc.so entirely and only staticly linked, so processes that didn't use them wouldn't even have them in their address space, and ones that did would have them at less predictible addresses?
Right now, I'm thinking only of functions that end up calling
execve(); are there any other sufficiently powerful interpreters hiding in common system libraries?regexec()?Quoted 6 lines
This does absolutely nothing to stop an exploit from providing its own inline version of
execve(). There's nothing in libc that a process can't do itself, inline.A better bet is using an LSM module that prohibits
exec()calls from any unauthorized combinations of running program/user/etc.Is that practical? I can see how with some daemons it would definitely be useful to prohibit exec calls (maybe things like BIND don't need to exec anything).. but some daemons do need to exec. An SMTPD may need to
exec()some helper processes (postfix for instance has a whole slew of helper programs it uses).. and things like sshd need to exec a shell, etc..
Quoted 4 lines
It's still a good idea though, since some daemons don't need to exec, ever. I guess this is one extra layer of protection. As Ingo said in his announcement, the more layers of protection you have, the better.. and the more difficult a cracker's job is.
would be easier to make a CAP_EXEC capability that bind can drop then ;)
Quoted 16 lines · Calin A. Culianu
Quoted 15 lines · On Sat, 3 May 2003 [email protected] wrote:
Quoted 9 lines · On Sat, 03 May 2003 13:19:52 -0000, [email protected] said:
An interesting question arises: is the number of useful interpreter functions (system, popen, exec*) sufficiently low that they could be removed from libc.so entirely and only staticly linked, so processes that didn't use them wouldn't even have them in their address space, and ones that did would have them at less predictible addresses?
Right now, I'm thinking only of functions that end up calling
execve(); are there any other sufficiently powerful interpreters hiding in common system libraries?regexec()?This does absolutely nothing to stop an exploit from providing its own inline version of
execve(). There's nothing in libc that a process can't do itself, inline.
Quoted 8 lines
Quoted 2 lines
A better bet is using an LSM module that prohibits
exec()calls from any unauthorized combinations of running program/user/etc.Is that practical? I can see how with some daemons it would definitely be useful to prohibit exec calls (maybe things like BIND don't need to exec anything).. but some daemons do need to exec. An SMTPD may need to
exec()some helper processes (postfix for instance has a whole slew of helper programs it uses).. and things like sshd need to exec a shell, etc..
What you actually would do is have the LSM module turn exec into MAY_EXEC_IF where the IF is done to match security context information to the binary being execed. ssh shouldn't exec (well most of the time anyway) a root shell. Instead it should switch security context, (including a security id and uid's/gids) first, then exec if the new security context is valid for what is being execed. (and the new securid is not necessarily selected from kernel mode - it may depend on network connection + user id/gids requested + security level permitted)
More complicated, but the full security context being switched to cannot be selected by the application itself.
Quoted 4 lines
It's still a good idea though, since some daemons don't need to exec, ever. I guess this is one extra layer of protection. As Ingo said in his announcement, the more layers of protection you have, the better.. and the more difficult a cracker's job is.
true.
Quoted 9 lines · On Sat, 03 May 2003 13:19:52 -0000, [email protected] said:
An interesting question arises: is the number of useful interpreter functions (system, popen, exec*) sufficiently low that they could be removed from libc.so entirely and only staticly linked, so processes that didn't use them wouldn't even have them in their address space, and ones that did would have them at less predictible addresses?
Right now, I'm thinking only of functions that end up calling
execve(); are there any other sufficiently powerful interpreters hiding in common system libraries?regexec()?
To which Valdis.Kletnieks replied:
Quoted 3 lines
This does absolutely nothing to stop an exploit from providing its own inline version of
execve(). There's nothing in libc that a process can't do itself, inline.
Ah, but with a non-executable stack, how do you arrange the inline code? if you include it in the buffer overflow on the stack, it's in the non-executable range.
You could arrange a return to memcpy(), with a stack like this:
[Address of memcpy()]
[Exploit target address (return address from memcpy)] [Exploit target address (destination of memcpy)] [Address of code on stack (source of memcpy)] [Length of code on stack]
[Exploit code]
This would work if you had an "exploit target address" that was writeable and executable, which this could copy the code to, but that's hard to come by.
Now, we could stick a call to mprotect on the stack before that, but it's hard to get the protection flags past the kernel test:
mm/mprotect.c, like 237:
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM))
return -EINVAL;
When your exploit can't include any null bytes.
Arjan's idea about a CAP_EXEC would be better, if it could be dropped automagically by linker magic on existing code.
In fact, there are several other capabilities that would be nice to have droppable:
- Ability to open an existing regular file or device (seekable, persistent storage) for writing. An SMTP daemon could probably drop this.
- Ability to create an externally accessible listening socket (listen() on non-PF_UNIX)
- Ability to connect to an external address (connect() on non-PF_UNIX)
The PF_UNIX exception is for /dev/log.