Re: [RFC][PATCH] exec: Use init rlimits for setuid exec
From: Linus Torvalds
Date: Fri Jul 07 2017 - 12:22:52 EST
On Thu, Jul 6, 2017 at 11:40 PM, Kees Cook <keescook@xxxxxxxxxxxx> wrote:
> On Thu, Jul 6, 2017 at 10:49 PM, Kees Cook <keescook@xxxxxxxxxxxx> wrote:
>
> At Andy's suggestion I'm using security_bprm_secureexec() to test for
> setuid-ness. However, this seems to expect the credentials to have
> already been installed.
That function actually takes a look at current creds, so yes, it
currently works only after the creds have been installed.
It works for you because it *also* checks if the current cred is not
root, and then it looks at bprm->cap_effective too (indirectly - check
the commoncap code), which has been set earlier.
But it's crazy code. I literally don't know why it looks at
current_creds(), when it's all about the bprm, which has its own creds
- and then it would work any time.
That code is confusing. Somebody should check it. That whole
security_bprm_secureexec() hook seems mis-designed.
> And yet ... the following patch still works correctly when I call it "early".
So I definitely like this approach, as long as we clarify that crazy
security_bprm_secureexec() model. That code really is insane.
But I wonder:
> + if (security_bprm_secureexec(bprm)) {
> + struct rlimit default_stack = { _STK_LIM, RLIM_INFINITY };
> +
> + current->signal->rlim[RLIMIT_STACK] = default_stack;
Should we override the whole thing? And in particular, should we
override the hard limit at all?
If we have an existing lower stack limit, we might as well leave it be
entirely. And if the soft stack limit is higher, why modify the hard
limit?
In particular, the scenario I'm thinking of is "system admin on a
small machine has set everybodys stack limits to just 8M as a _hard_
limit".
Now, Bob and Jill agree to help each other to escape that limit, so
they make suid binaries for their own account, and let each other use
them - boom, they now have _STK_LIM and RLIM_INFINITY stack limits.
Not good.
In contrast, if the code just did:
if (security_bprm_secureexec(bprm)) {
if (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM)
current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM;
}
and leave the hard limit alone entirely. At least that doesn't let
anybody escape the limits that the sysadmin has set.
Hmm? Yes, this allows people to try to attack suid binaries with a
really small stack. But that's a pre-existing attack - do we have
worries about it?
Linus