On 6/8/19 10:08 AM, Daniel Walsh wrote:
On 6/7/19 5:26 PM, Stephen Smalley wrote:
On 6/7/19 5:06 PM, Daniel Walsh wrote:
On 6/7/19 12:44 PM, Stephen Smalley wrote:
On 6/7/19 11:42 AM, Daniel Walsh wrote:
We have periodic vulnerablities around bad container images having
symbolic link attacks against the host.
One came out last week about doing a `podman cp`
Which would copy content from the host into the container. The issue
was that if the container was running, it could trick the processes
copying content into it to follow a symbolic link to external of the
container image.
The question came up, is there a way to use SELinux to prevent
this. And
sadly the answer right now is no, because we have no way to know what
the label of the process attempting to update the container file
system
is running as. Usually it will be running as unconfined_t.
One idea would be to add a rule to policy that control the
following of
symbolic links to only those specified in policy.
Something like
SPECIALRESTRICTED TYPE container_file_t
allow container_file_t container_file_t:symlink follow;
Then if a process attempted to copy content onto a symbolic link from
container_file_t to a non container_file_t type, the kernel would deny
access.
Thoughts?
SELinux would prevent it if you didn't allow unconfined_t (or other
privileged domains) to follow untrustworthy symlinks (e.g. don't allow
unconfined_t container_file_t:lnk_file read; in the first place).
That's the right way to prevent it.
Trying to apply a check between symlink and its target as you suggest
is problematic; we don't generally have them both at the same point.
If we are allowed to follow the symlink, we read its contents and
perform a path walk on that, and that could be a multi-component
pathname lookup that itself spans further symlinks, mount points,
etc. I think that would be challenging to support in the kernel,
subject to races, and certainly would require changes outside of just
SELinux.
If you truly cannot impose such restrictions on unconfined_t, then
maybe podman should run in its own domain.
This is not an issue with just podman. Podman can mount the image and
the tools can just read/write content into the mountpoint.
I thought I recalled a LSM that prefented symlink attacks when users
would link a file in the homedir against /etc/shadow and then attempt to
get the admin to modify the file in his homedir?
I was thinking that if that existed we could build more controls on it
based on Labels rather then just UIDs matching.
Not sure if you are thinking of symlink attacks or hard link attacks.
SELinux supports preventing the former by restricting the ability to
follow symlinks based on lnk_file read permission, so you can prevent
trusted processes from following untrustworthy symlinks. SELinux
supports preventing the latter by restricting the ability to create
hard links to unauthorized files. But you need to write your policies
in a manner that leverages that support, and a fully unconfined domain
isn't going to be protected via SELinux by definition; ideally you'd
be phasing out unconfined altogether like Android did. Modern kernels
also have the /proc/sys/fs/protected_hardlinks and
/proc/sys/fs/protected_symlinks settings, which restrict based on UID,
but the symlink checks aren't based on the target of the symlink either.
Android does not have an Admin, so it is a lot easier for them. But not
going to get into that now. I obviously understand how SELinux works.
But perhaps I am looking for something differntly.
This link defines pretty close to what I would want, but extended for
labels rather then just UIDS.
https://sysctl-explorer.net/fs/protected_symlinks/
A long-standing class of security issues is the symlink-based
time-of-check-time-of-use race, most commonly seen in world-writable
directories like /tmp. The common method of exploitation of this flaw
is to cross privilege boundaries when following a given symlink (i.e.
a **PRIVILEGED** process follows a symlink belonging **PROVIDED BY
OTHERS**). For a likely incomplete list of hundreds of examples across
the years, please see:
http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp
When set to “0”, symlink following behavior is unrestricted.
When set to “1” symlinks are permitted to be followed only when
outside a sticky world-writable directory **WE COULD POTENTIALLY SET
THIS OR SOME OTHER FLAG**, or when the **LABEL** of the symlink and
follower match, or when the directory **LABEL** matches the symlink’s
**LABEL**.
This protection is based on the restrictions in Openwall and grsecurity.
That's the /proc/sys/fs/protected_symlinks feature I mentioned in my
email above. It isn't based on the target of the symlink; it is only
based on the attributes of the follower process (e.g. root), the
attributes of the parent directory containing the symlink (e.g. /tmp),
and the attributes of the symlink file (e.g. /tmp/foo -> /etc/shadow).
At no point is it checking anything about the target of the symlink,
e.g. /etc/shadow. If dwalsh creates a symlink under /tmp (ln -s
/etc/shadow /tmp/foo) and root tries to follow /tmp/foo, then that will
fail because 1) the process fsuid (root) != the /tmp/foo symlink owner
(dwalsh), and 2) /tmp is a sticky and world-writable directory, and 3)
the /tmp directory owner (root) != the /tmp/foo symlink owner (dwalsh).
Note that conditions (2) and (3) render the check useless for your use
case, since you want to prevent following any symlinks writable by
container processes in any directory within the container filesystem, so
the directory need not be world-writable/sticky and the parent directory
UID/label might be identical to the symlink UID/label.
The existing SELinux lnk_file read permission check enables you to apply
stronger label-based controls to all symlinks within the container
filesystem, not just ones in /tmp-like directories. Don't allow
unconfined_t or any other privileged domain read permission to
container_file_t:lnk_file (or preferably to any file type for which
:lnk_file create is allowed to container process domains), and you'll
never have to worry about them following a symlink writable by a
container process. This of course assumes that the container filesystem
is always labeled with a type that is untrusted, whether via mount
contexts or actual labels.