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