Discussion:
SELinux security and passed file descriptors
David Howells
2007-08-30 15:12:14 UTC
Permalink
Hi Stephen,

Imagine you have two processes, say A and B, running with different security
contexts. If A opens a file and passed the file descriptor to B (sends it
over an AF_UNIX socket perhaps), then what security context should be assumed
when B operates on the file descriptor? A's security, or B's?


I would have thought it should be A's security, since A opened the file. This
is usually the case for UID/GID/mode information (which are resident on the
file struct) and other FS-specific access contexts (in the in-kernel AFS's
case, this includes the kerberos ticket A used to access the file, and I
believe the same is true in NFS's case).


However, having just been looking through security/selinux/hooks.c, this isn't
always the case with SELinux. For ioctls, for example, B's security context
will be used. The same goes for reading and writing.

This is surely incorrect. This can mean A can pass a file that it can read
and write to B that B can't then read or write because it doesn't have access,
even though it ought to be able to because *A* can.

At least, that's how I interpret the code.


If I'm right, and this is incorrect behaviour, then I have most of a patch
that I'm working on to pass the appropriate credentials around.

David
-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephen Smalley
2007-08-30 15:19:55 UTC
Permalink
Post by David Howells
Hi Stephen,
Imagine you have two processes, say A and B, running with different security
contexts. If A opens a file and passed the file descriptor to B (sends it
over an AF_UNIX socket perhaps), then what security context should be assumed
when B operates on the file descriptor? A's security, or B's?
I would have thought it should be A's security, since A opened the file. This
is usually the case for UID/GID/mode information (which are resident on the
file struct) and other FS-specific access contexts (in the in-kernel AFS's
case, this includes the kerberos ticket A used to access the file, and I
believe the same is true in NFS's case).
However, having just been looking through security/selinux/hooks.c, this isn't
always the case with SELinux. For ioctls, for example, B's security context
will be used. The same goes for reading and writing.
This is surely incorrect. This can mean A can pass a file that it can read
and write to B that B can't then read or write because it doesn't have access,
even though it ought to be able to because *A* can.
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. And it has caught any number of bugs in applications as well as
the kernel where a descriptor is unwittingly leaked across exec.

Now, we do revalidate access to open files when they are passed across
local IPC (see selinux_file_receive) and when they are inherited across
an exec that changes SIDs (see selinux_bprm_post_apply_creds ->
flush_unauthorized_files), so we don't strictly need the rechecking of
access on read/write to control propagation.

The rechecking of access on read/write is instead to permit revocation
of access upon file relabels (setxattr) and policy changes (boolean
change or reload). However, that doesn't give us complete coverage
(e.g. mmap'd file or in-progress operation that has passed the check).
If/when the revoke support ever gets to a usable state and is merged, we
might use that instead, i.e. do a selective revoke if access is no
longer granted to the new file label or under the new policy upon
setxattr or policy change rather than rechecking on use. But I'm not
sure how well that will work.

There is also some discussion going on presently about optimizing
selinux_file_permission, e.g. only rechecking under certain conditions
(any one of process SID, file SID, or policy seqno has changed since
open-time check).
Post by David Howells
At least, that's how I interpret the code.
If I'm right, and this is incorrect behaviour, then I have most of a patch
that I'm working on to pass the appropriate credentials around.
--
Stephen Smalley
National Security Agency

-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
David Howells
2007-08-31 14:32:15 UTC
Permalink
Post by Stephen Smalley
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.

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?

I don't think you can practically change the security attached to the file
struct,

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).
Post by Stephen Smalley
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.


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.

David
-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephen Smalley
2007-08-31 15:01:44 UTC
Permalink
Post by David Howells
Post by Stephen Smalley
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.
Post by David Howells
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.
Post by David Howells
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?
Post by David Howells
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.
Post by David Howells
Post by Stephen Smalley
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.
Post by David Howells
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 ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Casey Schaufler
2007-08-31 15:39:43 UTC
Permalink
Post by Stephen Smalley
Post by David Howells
Post by Stephen Smalley
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
Post by David Howells
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.
Stephen is correct. Some of the Unix MLS systems went so far as to
prohibit passing file descriptors all together. The ability to pass file
descriptors is one of those things that make one wonder what could
possibly have been going through the mind (or bloodstream) of the
original author. Yes, I understand that it is useful. It is also one
of those fringe cases that makes it really hard to protect a system
against clever programmers. SELinux currently treats the mechanism
with more respect than it needs to. I expect that in the grand scheme
of things we'd all be better off if the mechanism where abandoned
before the exploits get too thick and someone adds a half dozen layers
of complexity to address the issues one by one.

But, that's just me.





Casey Schaufler
***@schaufler-ca.com
-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Mikel L. Matthews
2007-08-31 15:46:02 UTC
Permalink
Post by Stephen Smalley
Post by David Howells
Post by Stephen Smalley
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.
How about looking at it this way, I am work for company A and therefore
I can see all of their engineering documents. You work for company B and
are not supposed to see any of our engineering documents. Company A's
policy states that I can't disclose company private information to any
one who is not cleared for it. So by giving you access to this
information (either by telling you (e.g., passing a file descriptor) or
handing you a document) I am in violation of company policy. MAC is
there to enforce the company policy so I won't give you the information
you are not supposed to have.
Post by Stephen Smalley
Post by David Howells
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.
Or B is a privileged (trusted) process that can raise/change the correct
privilege/capability/context to access the information/descriptor.
--
Thanks,
Mike
----
Mikel L. Matthews
Chief Technology Officer
Innovative Security Systems, Inc. (dba Argus Systems Group)
1809 Woodfield Dr.
Savoy IL 61874
+1-217-355-6308
www.argus-systems.com

"Any intelligent fool can make things bigger, more complex, and more
violent. It takes a touch of genius - and a lot of courage - to move
in the opposite direction."
Albert Einstein
-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Al Viro
2007-08-31 16:03:43 UTC
Permalink
Post by Mikel L. Matthews
Post by Stephen Smalley
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.
How about looking at it this way, I am work for company A and therefore
I can see all of their engineering documents. You work for company B and
are not supposed to see any of our engineering documents. Company A's
policy states that I can't disclose company private information to any
one who is not cleared for it. So by giving you access to this
information (either by telling you (e.g., passing a file descriptor) or
handing you a document) I am in violation of company policy. MAC is
there to enforce the company policy so I won't give you the information
you are not supposed to have.
... except, of course, the fact that there's nothing to stop you from talking
to me over the same channel and marshalling all IO to that file.

Frankly, a much saner alternative would be to have file-passing as
_replacement_ for any capabilities-changing mechanisms (i.e. "has
capability" == "has the right opened file available" and "gain capability"
== "talk somebody who grants it into passing such file to you"). But that
would be a different system with differently designed userland...
-
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
James Antill
2007-08-31 15:39:43 UTC
Permalink
Post by David Howells
Post by Stephen Smalley
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.
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?
It doesn't, that's what the _Mandatory_ part of Mandatory Access
Control is all about.
See the third paragraph from wikipedia, on MAC:

"""MAC's most important feature involves denying users full control over
the access to resources that they create. [...] """

http://en.wikipedia.org/wiki/Mandatory_access_control
Post by David Howells
I don't think you can practically change the security attached to the file
struct,
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).
This is correct, and often happens with respect to stdout (see
allow_daemons_use_tty etc.).

You might also be asking how you can run B in the same security context
as A, and you can do that by calling setexeccon() with the result from
getcon(). But that is very likely to affect more than just writing to
stdout.
Or you could call fsetfilecon() on stdout from A, so that it would be
in a context that B could use, but that might not be allowed (or just be
a bad idea).
--
James Antill <jantill-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
Loading...