On Fri, 2007-08-31 at 15:32 +0100, David Howells wrote: > Stephen Smalley <[EMAIL PROTECTED]> wrote: > > > That's how mandatory access control is supposed to work; otherwise, a > > flaw in A can leak the descriptor to B at will in violation of security > > policy. > > Yeah, but by making it impossible to have the flaw, you've also made it > impossible for A to validly pass to B a file descriptor B wouldn't otherwise > be able to access directly, but should be able to access on behalf of A.
Let me say it again: that's how mandatory access control is supposed to work. A program (or user) isn't supposed to be able to delegate access under a mandatory policy. > To put it another way, how does A now legitimately pass on to B the grant of > rights A had on that specific file descriptor? That would be discretionary, and therefore vulnerable to flawed and malicious code. That's the point. > I don't think you can practically change the security attached to the file > struct, SELinux already ensures that a process cannot inherit or receive a descriptor to which it isn't authorized access. What isn't practical about that? > With respect to execve(), imagine that program A (a shell, say) opens a file > to use as a stdout for program B, which it then proceeds to exec. Imagine, > however, the process's security label is changed during the exec of B and this > disallows B from writing to its stdout. Is this correct behaviour since it is > differs depending on whether SELinux is in enforcing mode or not? Or is there > some way around this in SELinux? (I presume this is what > flush_unauthorized_files() does). It is correct behavior to close the descriptor in that case, yes, and that is what flush_unauthorized_files does. > > And it has caught any number of bugs in applications as well as the kernel > > where a descriptor is unwittingly leaked across exec. > > Whilst that may make it a useful debugging tool, it doesn't necessarily make > it a good policy. It prevents unauthorized propagation of access rights in the system, which is required to enforce a mandatory policy. Suppose that we have two processes A and B, and A is allowed to send to B but not vice versa (unidirectional channel, used to upgrade information). If A can send a descriptor to B and B can use the descriptor based solely on A's credentials, then that unidirectional channel can be leveraged to create a reverse channel via a file descriptor passed across it, and now we have no information flow control. Suppose that we have a protected/trusted subsystem A that is responsible for mediating all data flow to a given file, where A performs some kind of checking or transformation (access control, encryption, sanitization, whatever). We want to ensure that only A can write to the file directly, but we are fine with a client process B sending data to A to be checked/transformed by A and then written to the file by A. If A leaks a descriptor to the file to B and B can use the descriptor solely based on A's credentials, then B can now bypass the checking or transform and we have no integrity protection there. > Btw, surely selinux_file_receive() is redundant because all that it checks is > whether B can naturally access the file, which surely read and write, etc, > will check anyway. OTOH, although it appears to be redundant, I suppose it > eliminates the use of the file as soon as possible. Closing the descriptor at the point of a transition/transfer (on exec or receive) is more reliable and seems better from an error handling point of view. As I said, the read/write checks are more for revalidation to handle file relabels and policy changes, and we'd be willing to replace those with a revoke-based mechanism if one existed and could be used to the same effect. -- Stephen Smalley National Security Agency - To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html