tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: core statement on fexecve, O_EXEC, and O_SEARCH



On Tue, Dec 04, 2012 at 11:42:04PM +0700, Robert Elz wrote:
> 
> First, I'm not sure it is really worth fixing at all, this doesn't
> seem to be a particularly big problem in reality.  But, that said,
> if a file exists, has x permission, and there's something executable
> behind it, then exec should work on it, and there really should be
> no need to look further than that.

I strongly disagree.  This system call embodies a fairly fundamental
shift away from the Unix model that object permissions are checked
when you get a handle to an object -- not when you use that handle.

Here, you can open a file for read, and if it goes +x later, you can
execute it then; you can open it for read, when you have execute
permission on it, and suddenly find later that you can't.  I think
that is not a small change and that it should be considered very
carefully.

I bounced this around with my officemates again a few days ago and
we landed at the conclusion that the mode-when-opened should follow
the file descriptor around in cases like this, but that the least-surprise
way to use it is that the file should be required to be executable by
you *both* when opened *and* when later fed to the f*() syscall.  Given
that and some other changes, I think this could be made safe -- but it
is not so terribly obvious to me as it seems to you that this kind of
basic change in how file permissions are checked could necessarily
be, much less is necessarily, safe.

>   | Some questions that I would like to see answered are: Should it 
>   | be possible to exec a fd only if a special flag was used in the 
>   | open(2) call?
> 
> The questin here isn't really execing a fd, its execing a named file
> (that happens to refer to an open fd, bt that shouldn't be important).

Of course it's important.  Just like fchdir(), fchroot(), fhmod() etc. to
really check properly may require reversing the inode-to-name mapping -- the
results of which may be ambiguous.

>   | Should the file's executability be checked at open 
>   | time or at exec time, or both,
> 
> For this use, at exec time, the fd refers to a file, this should be
> not be different than an exec of a symlink.   We just have a slightly
> different way if getting a reference to the file to be exec'd.

I think this is wrong, for two reasons:

        1) In the symlink case, you have a name, and nothing can change
           the permissions on the file associated with the name in question
           between when you look it up and when you execute it.  Here,
           minutes, hours, or days can pass, and so that's not the case.
           The symlink case does not involve the fundamental shift away
           from the Unix model of checking permissions when you look up
           the name that this does.

        2) In the symlink case, it is not possible for the question of the
           file's name to be unanswerable.  What happens if you try to
           fexecve() a descriptor whose name has been unlinked, for example?

[...]
> Even chroot isn't a problem, unless you're tempted to view it as some
> kind of security mechanism.   It really isn't - it is just namespace
> modification.

Again I strongly disagree.  The chroot system call isn't, itself, a
security mechanism, but it can be an important building block for such
mechanisms.  It is the only means of namespace restriction we have.

By restricting a process' access to the namespace, and appropriately
restricting executability and writability in the portions of the namespace
the process can access, it can be possible to set a process running in a
little mini-TCB within the larger system, so that one can make provable
assertions about what code can actually end up running no matter what the
process does.  The fact that not every use of chroot achieves an appropriate
security-related goal does not, itself, establish that not any use of chroot
does so; but you seem to reason as if it does.

If we decided to implement this new system call (which, given the colossal
design mistake with O_EXEC, we may not want to do, since we cannot implement
it in a way that conforms to the standard) I think we need to track and
use some additional information for every descriptor:

1) What the owner and mode of the file were when it was opened
2) What the name for the file was when it was opened
3) Whether the descriptor has ever been passed on a socket

I think we might to add a socket option that allows descriptors
passed on a socket to be fed fexecve, and forbid it otherwise.  (Though
as I think about it, this still may not be entirely safe).  I also think
we need to check, for all the fch*, fexec* syscalls:

        * permissions both retained from the file's open and at the time
          of use

        * whether the name in question still refers to the file in question

        * whether the name in question is within the process' current root
          (forbidding fchdir and fchroot otherwise).

Thor


Home | Main Index | Thread Index | Old Index