[apparmor] sshd and profile transitions

John Johansen john.johansen at canonical.com
Wed Sep 30 19:51:06 UTC 2015


On 09/30/2015 08:08 AM, Simon Deziel wrote:
> On 09/29/2015 05:56 PM, John Johansen wrote:
>> On 09/29/2015 02:25 PM, Simon Deziel wrote:
>>> Hi everyone,
>>>
>>> My sshd is contained by the attached profile (also available here [1]).
>>> Once logged in via SSH, I have an unconfined shell, at least according
>>> to "ps Zaux | grep $$". As such, I would expect to be able to run
>>> everything as usual but if I run a binary contained by Apparmor (like
>>> tcpdump) I get the following denials:
>>>
>>> apparmor="DENIED" operation="file_inherit" profile="/usr/sbin/tcpdump"
>>> name="/dev/pts/0" pid=1529 comm="tcpdump" requested_mask="wr"
>>> denied_mask="wr" fsuid=0 ouid=0
>>> [...]
>>> apparmor="DENIED" operation="getattr" info="Failed name lookup -
>>> disconnected path" error=-13 profile="/usr/sbin/tcpdump"
>>> name="apparmor/.null" pid=1529 comm="tcpdump" requested_mask="r"
>>> denied_mask="r" fsuid=0 ouid=0
>>>
>> Okay, so apparmor is checking all the open file descriptors that tcpdump
>> is inheriting. Ones that are not allowed are being "closed" during the
>> file inherit pass. I say "closed" because we don't actually close the
>> file, the associated file descriptor may have significance to the
>> application, eg fd 1 is stdout, etc. It is entirely possible the parent
>> is passing an open file, and the fd # by args or environment etc. Truly
>> closing the fd would make it available for reuse and that could cause
>> strange failures.
>>
>> So instead of actually closing the file, apparmor redirects its to be a
>> file to a special null device that apparmor sets up. In most cases
>> (reads and writes) will not result in further logging, but some cases
>> like getattr will result in logging extra denials about access to
>> "apparmor/.null". This is just an artifact of how the lsm is setup, and
>> how apparmor is handling things internally atm.
> 
> Interesting. Just to make it clear, I not only get logs but actual
> denials as I cannot see any output from the packet captures. Saving the
> trace to a file (-w) or using a shell redirection works though.
> 
Correct, these are actual denials. Specifically you get 1 file_inherit
denial when apparmor replaces the open file. Reads and Writes to the
file are redirected to the special null device so their is no denial,
but other operations like getattr, setattr, etc will result in a
denial to access the null object.

> The inheritance thing is still a bit unclear to me. The AA contained
> sshd process launches an uncontained bash process for my session so why
> is AA still looking around for what's happening in that uncontained bash?
> 
So processes can pass open files down to their children, and those children
can pass those files down to grandchildren etc. The open files take up
resources in the processes descriptor table and have position and other
information associated with them.

So don't think of it as what is happening in the unconfined bash. The
file is opened under confinement, during a domain transition (sort of
in the original profile), certain resources are determined as not being
allowed access on the other end of the transition.

These resources instead of being closed are replaced with a special file
object, because the child will not have access to it, even if the child
or grand child does. It is true that an unconfined process is free to
open the original files itself, but it can not access the special null
file. So what is happening is during a transition the the file is
duped (look up man 2 dup) to the special null file, and then at some
point unconfined is getting this already opened file. This file no
longer points to or references the original file in anyway, is all the
unconfined process sees is the special null file which everyone (including
unconfined) is denied access to.

Unconfined is free to access the original file if it opens it directly.
Or receives the file in such a way that it has not gone through an
inheritance chain that ends up duping the file to the special null.

As an aside, we have to be very careful about what gets passed from
one process to the next during a profile transition as this can be a
means of elevating privileges.

>> Ideally we will get
>> around to fixing these cases to not log as well, but we have a lot of
>> higher priority items to tackle first.
> 
> Understood.
> 
>>> Adding "/dev/pts/[0-9]* rw" to the tcpdump profile fixes the problem but
>>> it seems like the wrong way. FYI, this also happens with other programs
>>> confined by AA.
>>>
>> yeah I agree that it is the wrong way, but unfortunately atm it is what
>> needs to be done. Really the parent should be delegating access of the
>> pts fd to its child. However this ability has not landed yet. It will
>> come, without apparmor is stuck doing an ambient authority which is not
>> what we want.
> 
> Is it this ambient authority behavior that explains why AA still
> mediates the uncontained bash process and thus prevents a clean
> transition to tcpdump in that chain:
> 
> sshd (contained) -> bash (uncontained) -> tcpdump (contained)
> 
partially, and partially an implementation detail about how resources
are passed through processes. Some things get scrubbed others don't.
Eg. the file gets duped to null but if the file name had been passed as
an environment variable and tcpdump had opened it directly then things
would behave differently.

I am not a fan of the dup to null behavior but it is required to ensure
that applications don't break in different ways. Eg. say the file on fd 2
(stdout) is determined to be not allowed. If we close the file for that
process fd 2 becomes the next available fd, and when the process opens
its first file it gets opened on fd. So that first file also becomes
the processes stdout for the length that it is held open.

This type of thing is less likely with fds > 3 but if for some reason
the application receives info that a file was passed on a given fd
it may try using it directly as well (this does happen).

> 
>>> My last attempt was to give sshd access to all the existing capabilities
>>> but it didn't help. I tried that because I noticed that sys_ptrace could
>>> be missing from a profile without any denial being logged.
>>>
>> Hrmm interesting that if sys_ptrace is missing no denial is logged. I'm not
>> sure what is going on there. Will have to dig to say anything more
> 
> I'm not sure what goes on but I know special conditions need to be meet
> to reproduce.
> 
> So when /proc is mounted with hidepid>=1 and sshd isn't allowed to
> sys_ptrace, pam_limits is unable to access /proc/1/limits to obtain the
> default RLIMITs so it logs this:
> 
> sshd[2203]: pam_unix(sshd:session): session opened for user simon by (uid=0)
> sshd[2203]: pam_limits(sshd:session): Could not read /proc/1/limits (No
> such file or directory), using PAM defaults
> sshd[2203]: pam_limits(sshd:session): Did not find kernel RLIMIT for
> cpu, using PAM default
> [...]
> 
> 
interesting

> While it certainly qualifies as an edge case, an AA log would have been
> helpful :)
> 
of course, however in this case it looks like other parts of the kernel
are blocking things before it reaches apparmor. Sadly the kernels security
framework is split between multiple checks so that no one subsystem could
be said to be authoritative.

>>> Any hints on what's going on here would be greatly appreciated.
>>>
>> hopefully the above explanation fills in the gaps, if not let me know
> 
> It helps that's for sure.
> 
> Thank you very much!
> 
> Simon
> 
> 
> 




More information about the AppArmor mailing list