[apparmor] File delegation

John Johansen john.johansen at canonical.com
Fri Dec 9 00:48:28 UTC 2011


CCing: Rob Meijer, he is the author of minorfs which is a filesystem that
provides delegation in cooperation with apparmor.  At one point in the past
Rob proposed extending apparmor with delegation and for various unfortunate
reasons was told no.

So Rob basically this is a discussion about the merits of sticking delegation
into apparmor.  I think your insight into how the split between minorfs as a
separate file system to handle delegation and apparmor, has worked out would
be invaluable.


On 12/08/2011 03:17 PM, Ángel González wrote:
> How hard would it be to have a dynamic list of rules (paths) per process?
> They would need to be on a different structure than the dfa, not shared
> between instances.
> 
> In this old mail you mentioned file delegation as passing an open file, but
> I'd extend that to delegation of full paths, so programs don't need to
> be changed,
> yet only include their requisites in their dfa.
>

It possible though it would certainly slow things down, the longer the list
becomes.  The question is what defines what can be delegated?  If its
something dynamic, eg. the open files then tracking the information on the
opne fds that are passed is better.

If its defined by the policy then it can be done statically by composing
with the profile at compile time.

The only place that it makes sense to track this as a list is when a task
deliberately requests it via an api.  I am certain not opposed to this
but even then I think we still would want to indicate in policy what can
be delegated.

Implementation wise my current leans would be to use a compiled dfa as well,
but I would have to play with it more.  The down side would be making the
initial insertion would take a little longer, but if done right we could
actually use a single dfa for all the names that get delegated which would
improve performance if the file was accesses multiple times.

> On 06/08/10 01:05, John Johansen wrote:
>> File delegation (of authority) is the ability to pass an opened file to
>> a delegate task, giving it access to the delegated file even if the
>> policy being applied to the delegate would not ordinarily allow it.
>>
>> Delegation can allow for tighter profiles, while at the same time making
>> them more flexible (think of sec comp), the trade off being that the
>> profile no longer contains a static listing of all possible permissions.
>> This does make analysis of policy more difficult but it is still possible
>> using tools that can do flow analysis.
> 
> I view two ways of delegation:
> - Explicit delegation through a special interface (eg. writing the
> permissions and path
> to /proc/$PID/attr/delegations).
> - Automatic delegation by rules defined in the profile (eg. allow read
> access to argv[1]).
> 
> With the obvious restriction that the authorization must be a subset of
> that hold by the
> authoriser.
> 
sure this makes sense, I also see a desire to be able to control that subset
ie. what is delegated is a subset of what can be delegated which is a subset
of the rules within the profile

> 
> Why would this be useful?
> Let's take a look to a common case to be jailed: a profile for an
> internet browser.
> 
> We find rules such as:
>  # Default profile allows downloads to ~/Downloads and uploads from ~/Public
>   owner @{HOME}/Public/** r,
>   owner @{HOME}/Downloads/** rw,
> 
> This is annoying. Aunt Tillie should be able to upload
> @{HOME}/personal/photo1.jpg
> to facebook without having to make a copy in public before. And download to
> @{HOME}/funny/powerpoints/viewthis.pps without risking
> @{HOME}/work/report2011.pdf
> 
> And yet it's incomplete, as there could be a copy in
> ~/Downloads/report2011.pdf since last
> week when she downloaded it from gmail.
> 
> 
> IMHO with the above feature, this can easily implemented with a trusted
> program doing the
> Open/Save as dialog. When a 'Save as' is started, the library would
> route the call to that monitor
> (it's a library call, so no code changes needed in the end program, it's
> even doable by LD_PRELOAD)
> The monitor then shows a trusted dialog [1] where the user selects the
> file to open/write. Then, just
> before returning control to the browser, it increments the caller
> profile with that exact path [2].
> 
> This has been proposed before in the realm of chrooting a process and
> doing all accesses by fd-passing
> through a monitor, but that has the inconvenience of creating the chroot
> with all the needed files.
> AppArmor beautifully allows to solve it by allowing us to keep the
> process in the normal filesystem, but
> with access only to its files (eg. /usr/lib/*, ~/.mozilla/**).
> 
Yeah, this is a nice use case.  We have long wanted the ability to
have the file dialog be separated.  The biggest problem is that I am not
sure how feasible it is to replace application dialogs.  I do think it might
be easier to do it via filenames, than fd passing.

> 
> I proceed now to automatic delegation. The goal is to provide access
> just to the files the application is
> expected to use. How do you tell evince which pdf it should open? They
> could be anywhere in the filesystem,
> from /home, to /usr/share/docs, in /tmp or a cdrom inside /media. But no
> matter if the user opened it clicking
> the icon in a folder, or if it's the browser what launched it. It gets
> access to open it because that's how it's
> supposed to work. The file could be in its final location inside $HOME,
> at /tmp or inside ~/.mozilla/cache/0F3A/foo.pdf
> (where it would _usually_ not need to read anything). It just works.
> Worst case: the file contains evil javascript,
> exploits a buffer overflow and tries to send all your data to a zombie
> network. It isn't allowed to mess with
> anything but the given file (and in this instance even read-only!), so
> the adversary is defeated.
> 
> I have to admit that evince is an easy target, since it uses an instance
> per file and does only one thing. It's harder
> to make that isolation for processes which open new files in a existing
> instance. There the automatic delegation
> would need to catch the authorization flowing from the new instance to
> the old, in order to increase the credentials
> of the old one (I think they send the arguments through a socket, but
> will probably vary a lot between programs),
> and if that fat process went mad when opening that powerpoint, it could
> corrupt the document with the payroll
> you had open (in that case, opening the file needs to provide rw, so
> that Save "just works").
> If you want to open a suspicious document, you need to close the
> previous instance so that it isn't reused (the whole
> program, although with little code modification it could be changed to
> drop the privileges for that file when closing the
> document). Not much can be done from the outside. It's the program what
> needs to be changed. Either to spawn new
> instances or, if they need to be preloaded in memory, they could use a
> zygote which forks for each document with the
> appropiate rights.
> 
Yep I completely understand wanting this, its more a matter of argument
parsing is just ugly.  With that said there has been some work towards
extending environment variable filtering, which could also apply to
arguments.  The complex stuff would need a userspace exec helper but that
is something I think becomes in inevitable if we want to provide more
than just simple filtering, which it looks like we really do.

> 
> 
> I answer below the details for the other model, as there's an overlap
> betwen
> both also may also apply.
>> Beyond those basics there are several details to be determined.
>>
>> 1. Whether the delegatee profile should have rules controlling receiving of
>>    delegated files.
> The profile would contain what is being delegated (eg. second argument)
> and how.
> It would just specify in the profile the contract used by the program
> parameters.
> I don't think it should try to specify what profiles it could receive
> files from. On the
> contrary, it would be the caller, if any, the one to specify that "this
> call shouldn't
> delegate access".
> 
That is my general feel as well, I just wanted to throw out the question
for people to think about

> 
>> 2. Whether delegation rules should cover implicit, explicit delegation,
>>    or both.  For the purpose of this discussion, explicit delegation occurs
>>    when a task deliberately marks a file for delegation, where implicit
>>    delegation occurs when a file is passed without the task taking any
>>    explicit action to mark the file.
> As this proposal with paths, the rules would cover which strings get
> interpreted
> as paths, thus delegating the access. Attacks against this model would
> involve
> tricking a process into passing a capability unbeknown to it (eg. while
> it believes
> to be passing a caption). I find hard to trick an innocent app to pass
> an arbitrary
> string to a new (evil) process, though.
> 
Right delegation does open up an attack vector that ambient capabilities
doesn't have but I think in general its actually better than what the
ambient capability system provides as you have pointed out with apparmor
you often need to provide access to all the files in the home directory.

> 
>>
>> 3. How delegated files are inherited
>>    When a file is delegated to a child does the authority to access that 
>>    file also pass down to grand children?
>>
>>    Also can a child explicitly delegate a file it has inherited access 
>>    permission to?  That is the right to explicitly redelegate an open file 
>>    may be different than permission to implicitly inherit said file.
> I would allow subdelegation by default. Suppose the program were a shell
> script: it would *need* to pass the file to it's commands. But there
> could be a
> flag to restrict it.
> 
yep thats generally my feeling as well, trying to do any fine grained control
of subdelegation feels like it could get confusing and harry

>>
>> 4. How delegation should be expressed in policy
>>    So I don't have any great ideas on this, and suggestions are more than 
>>    welcome, basically it will depend on how much we want to be able to 
>>    specify and some of the choices made above.
> I don't have any preference. It could be something like:
>   argument "$1" rw
>   argument "$1~" rw
>   argument "$2-*" r
> 
hey this just re-enforces my notion to compile these things before handing
them to the kernel :)

> Note that a bit of parsing would be needed in the kernel to extract $1
> as the first
> argument which is not an option, or the argument for the "-o" option.
> They are straightforward, though.
> 
I am not opposed to parsing in the kernel, we have to do it for all kinds
of things, as long as its well defined so we can safely bound it.

> 
> Thanks for your patience reading so far :)
> You can voice now your objections.
> 
hehe, while I do love a good argument I think I basically agree.  fd
delegation is useful but is limited because not everything is pasted as
file descriptors.  However even with an explicit path delegation,
something still needs to be done with fd delegation, because there is
an aweful lot of fd passing happening.

Of course I would like to be able to make it so the policy author doesn't
need to deal with the differences as much as possible.



> 1- It's unspecified how it is done. The X11 protocol doesn't have
> provisions to easily do so. But
> although an integral part of making the whole secure, it should be
> solved separatedly.
> 2- The monitor would need a few per-process rules such as not only
> allowing $FILENAME, but also
> .$FILENAME.part
> 
> 



More information about the AppArmor mailing list