[Apparmor-dev] Re: execve() and CLOEXEC
Crispin Cowan
crispin at mercenarylinux.com
Sun Nov 25 00:45:11 MST 2007
Mark Seaborn wrote:
> Crispin Cowan <crispin at mercenarylinux.com> wrote:
>
>> Because of the nature of the API's, it is very easy for software to
>> mistakenly delegate permission by failing to close on exec, because
>> delegation across exec is the default behavior unless you block it. In
>> contrast, delegation over a socket cannot happen by mistake, you must
>> explicitly pass the FD through the socket. Therefore I am ok with the
>> idea that our policy control should only apply to passing via exec, and
>> we can trust that i software delegates over a socket, that it really
>> meant to do that. If we want to stop delegation by socket, then we need
>> to block the communication entirely.
>>
>
> OK, I agree with this, although I don't entirely agree with what you
> say earlier:
>
>
>> There is already such a system call. "man 2 fcntl" and look for the
>> CLOEXEC flag.
>>
>> The issue is that some software forgets to set this flag.
>>
>
> The problem is that software has to set this flag at all. The problem
> is that this interface (execve() + fcntl() + all the calls that add
> FDs to the FD table) is very easy to use in an unsafe way.
>
I think we are in violent agreement. The problem with delegation via
exec is that it is the default behavior to delegate, and the software as
to do something to stop it.
> But it is not very difficult to use execve() in a safe way: you just
> close all FDs except the ones you know you want to pass to the new
> program before calling execve(). (Performance is another issue. This
> assumes that there is an efficient way to close all but a specified
> set of FDs.)
>
> So execve() is unsafe, but it's easy to provide a wrapper around
> execve() that provides a safe interface. In the general case, a
> safe_execve() would take an array mapping from FD indexes in the new
> FD table to FD indexes in the current table. If it worked like this,
> it would be very similar to how capability arguments are passed in
> capability invocations on kernels like EROS/KeyKOS (albeit that
> execve() does not return).
>
That it is fairly easy to produce a safe way to program this stuff does
not instantly make all of the existing vulnerable software go away. So
while I encourage techniques like safe wrappers for execve() to address
this problem, that doesn't remove the need for an AppArmor policy
mechanism to block this vulnerability.
> I don't see this as different in principle to dealing with other
> unsafe interfaces. For example, buffer overruns are caused both by
> specific library interfaces that are unsafe (i.e. difficult to use
> safely, or too easy to use unsafely) and by the fact that the C
> language is not memory-safe. People have dealt with the buffer
> overrun problem at lots of different levels:
>
> * static analysis (the simplest being grepping for calls to gets() :-) )
> * glibc changes (checked versions of libc calls)
> * refactoring to use safer string abstractions
> * language changes (use a memory safe language)
> * compiler changes (checking canaries on the stack)
> * compiler + ABI changes (CCured, CapC)
> * kernel changes (address space randomisation)
> * even processor changes (non-executable stacks)
>
Interesting you should say that. I invented the canary checking defense
10 years ago. Today, nearly all code shipped is protected by canaries,
but it took a full 10 years to get to this state, and the canary defense
is *trivial* to apply, requiring no change to the source code at all.
> If you have a program that does not need to pass FDs across execve()
> (other than stdin/stdout/stderr), you could change its execve() call
> to close any offending FDs (perhaps logging a warning) or halt with an
> error if there are any offending FDs. Again, that can be done in the
> kernel or in glibc.
>
This is essentially what I propose: if the profile for a program does
not permit implicit delegation, the it closes the FDs on exec() whether
that was specified or not. But we can do that in AppArmor policy by
making FD delegation selectable, rather than by changing the programs or
libraries.
>>> Do you at least agree that it is a designation rather than a delegation
>>> that is the underlaying problem in the accedentaly passed Fd's?
>>>
>> I assume that "designation" and "delegation" are technical terms in the
>> OC space, so that just like "authority" means something very specific,
>> so do "designation" and "delegation". I just don't know what that
>> meaning is, so I can't answer your question yet.
>>
>> I've made this complaint before, it is an unfortunate habit of the OC
>> community to overload the meaning of common words such as "authority",
>> "permission", and in this case "designation" with specific technical
>> meanings. It confuses people from outside the community, and because the
>> technical terms are all common words, it makes it hard to google for.
>>
> Perhaps you should raise this issue on the cap-talk mailing list?
> (CC'ing cap-talk)
>
Complaining about well-established jargon in a discipline as old and
entrenched as Object Capabilities, is not going to do anything. I'm just
being a whiner because I didn't know what he meant.
> When Rob says that this is a designation problem rather than a
> delegation problem he means that the problem is that calls to execve()
> do not designate the FDs to pass.
>
So "designation" in OC means the way you specify (designate) the
capabilities to be delegated?
I find there is often simple translations of OC terminology. The most
important such observation of mine is that "authority" is precisely the
transitive closure via communications of permissions. "Designation"
appears to mean exactly what you might think it means, I was just
confused because most OC terms mean not quite what you think they might
mean :)
Crispin
--
Crispin Cowan, Ph.D. http://crispincowan.com/~crispin
CEO, Mercenary Linux http://mercenarylinux.com/
Itanium. Vista. GPLv3. Complexity at work
More information about the Apparmor-dev
mailing list