[apparmor] Retrofitting & access-control impedance mismatch for MinorFs

Rob Meijer rmeijer at xs4all.nl
Tue Jun 25 11:27:18 UTC 2013

On Tue, June 25, 2013 11:35, John Johansen wrote:
> On 06/24/2013 09:31 PM, Rob Meijer wrote:
>> On Mon, June 24, 2013 22:22, John Johansen wrote:
>>> On 06/24/2013 12:16 AM, Rob Meijer wrote:
>> That's amazing news. Could the above blocking of access to
>> /proc/$(pid_other_than_self)/fd/* be easily expressed in such a default
>> profile?
> So the trick to doing this with apparmor 2.x. Is loading policy in the
> initramfs, and then having early init re-exec it self so it picks up
> the loaded policy.
> Like I said it is a real pain
> You can do that in apparmor3 but it also adds the ability to define a
> default profile, that can be set as a kernel parameter. That profile
> starts in "unconfined" mode but can be replaced and start enforcing
> policy. Which allows us to get the policy load out of initramfs into
> early boot and is adequate if you trust your early boot process
>>>> I would really like to hear the thoughts of others on this
>>>> mailing-list
>>>> on
>>>> this. Should I give up on combining a retrofit version of MinorFs with
>>>> the
>>>> non-retrofit features of decomposition, attenuation and delegation?
>>>> Should
>>>> I add the confinement check for CapFs access or is this a futile
>>>> addition
>>>> that is to easily bypassed?  Or should I just provide a massively
>>>> permissive profile that could be used for all currently unconfined
>>>> processes and allows almost everything except for the specific places
>>>> under /proc where sparse-caps could be stolen?
>>> So if I was to do the restrictions via apparmor I would make a default
>>> profile
>>> and disallow access to the special files. Any process that needs access
>>> to
>>> a token file is under a different profile. So tighter than what you
>>> propose
>>> above, and you can have fairly loose special profiles that have access
>>> to
>>> a subset of the special files.
>>> I need to reread so of the minorfs details again before I could propose
>>> a
>>> solution in greater detail.
>> My problem is that if we have 3 processes running under the same uid:
>> Alice: AppArmor confined, pid=1000, has been delegated a process private
>>        directory by MinorFs that is freely accessible trough
>>        /minor-mnt/cap/rw-3ffc8f682cfab4f753d32a9182ebbe8e30e34e19/
>>        Alice has the following file currently open:
>>        /minor-mnt/cap/rw-3ffc8f682cfab4f753d32a9182ebbe8e30e34e19/foo.xml
>> Bob:   An other process, AppArmor confined, pid=1001, not programmed in
>> a
>>        way that makes it aware that it might be acting as a deputy. Bob
>> can
>>        not readlink /proc/1000/fd/*.
>> Mallet: An unconfined 'trojan' process, pid=1002. Mallet can readlink
>>        /proc/1000/fd/* and so 'steal' the sparse-cap to the private
>>        directory of Alice.
>> The ultimate solution is to keep Malet from stealing the sparse-cap.
>> An other alternative is to make /minor-mnt/cap/* inaccessible to Malet
>> by adding access control to the file-system that denies any access to
>> unconfined processes. This alternative however turns Bob into a
>> potential
>> confusable deputy. A third solution is to delegate trough an overlay
>> filesystem. This third solution however has major performance cost and
>> takes away the the ability to decompose,attenuate and delegate ones
>> private storage sub-tree to other processes.
>> If as you hinted the ultimate solution of a default 'deny sparse-cap
>> stealing' policy would be possible, this would take away the need to
>> choose between two relatively disagreeable options.
> right so a default profile could provide the ability to deny access to
> /minor-mnt/cap/*

Yes, but ideally the default policy (and most specific policies) could
deny access to something like @{PROC}/@{OTHERPID}/fd/*, that would solve
the whole problem.

Alternatively if/as-long-as this isn't possible either the default policy
or the CapFs file-system could deny access to /minor-mnt/cap/*, but as
stated this would result in the confused deputy issues as remaining
potential problem.

> Its a matter of how to setup this default. It can be done
> system wide:
> - From early boot by specifying the default profile (hard in 2.8)
> - Approximated with an early loaded default profile with attachment
>   specification (this technique changes pix, and pux behavior from
>   what would be had with the unconfined profile).  Also processes
>   started before the profile remain in the unconfined state.
>   eg.
>     profile default /** {
>       deny /minor-mnt/cap/* rw,
>       ...
>     }
>   This will attach to any executable but if a profile with a more
>   specific match is provided it will match first.
> per user:
> - pam_apparmor can be used to provide a default profile for each
>   user. So that the profile can be unique to the user.
> I feel like I am still missing something, as I am not fully understanding
> the confused deputy case.

Basically I think there would 3 distinct possibilities:

1) The default policy you describe helps to keep any non-special process
   from doing a readlink on  @{PROC}/@{OTHERPID}/fd/*. This would solve the
   whole issue. No performance price. No sacrificing functionality.
   No confused deputies.
2) CapFs is made to only allow /minor-mnt/cap/ access to higher lever
   MinorFs file-systems and these file-systems work as overlay file-system.
   There is no authority leakage possible, but there is a performance issue.
   Next to this, the ability to decompose,attenuate and delegate ones
   private storage sub-tree to other processes is sacrificed.
3) Either the default policy or the CapFs file-system could deny access to
   /minor-mnt/cap/*. This leaves open the confused deputy issue, but doesn't
   have the performance or functionality price of 2.

The issue with 3 would be that Malet could readlink for example
/proc/1000/fd/5 and gain access to the pseudo path for Alice her private
directory. Malet couldn't access this path herself, but Bob could. If
Malet can convince Bob to access the file on her behalf, than we have a
confused deputy problem.

I think its fair to conclude that '1' is the preferred option, and that
this preferred option depends on (at-least) AppArmor version 3 to be
sufficiently secure. Will AppArmor 3 allow expressing something like a
deny for @{PROC}/@{OTHERPID}/fd/* in a default policy? If so, what order
of magnitude timescale are we looking at for version 3?


More information about the AppArmor mailing list