[apparmor] AppArmor DBus mediation experimentation

John Johansen john.johansen at canonical.com
Thu Sep 22 00:37:15 UTC 2011


This is the first public airing of apparmor dbus mediation (there have
been some previous iterations that I didn't bother pushing out as they
where extremely buggy and killed dbus often).  It is still very
experimental, and at this point the policy language extension, and even
details of the mediation are still very much up in the air.

I know I have been talking about this for a while, sorry they have
taken so long, but hopeful most of the crashers are out of them.

I have stuck some 64bit debs up at
   people.canonical.com/~jj/aa-dbus.tgz


I'll work at getting the code up somewhere in next few days.  I don't
think its quite so important as its evolving and indeed the dbus
patch is an ugly hack, so we can play with it while a more generic
LSM like solution is developed.

A little about DBUS

DBus pretends to be object oriented, but in reality that how the upper language
binding layers are engineered.  The bus it self is really just a message passing
bus, with extra address information to support the object oriented upper layers.

A dbus address consists of
- socket/port that the task communicates with dbus over.   We ignore this in the
  dbus portion of the policy, but it is mediated by the file rules.
- connection/bus name.  Basically each new connection get a unique name like
   :34-907
  but a connection can acquire (bind) to a well known name (you only do this if
  you are providing a service)
   com.acme.Foo
- message/operation type.  method_call, signal, aquire, method_return, error
- object/path.  Yet another name for the "object" being communicated with.  They
  look like file paths.
   /com/acme/foo
- interface.  An object can support multiple interfaces, and message can specify
  which interface its intended for (this is only needed if two interface overlap).
  They look like connection/bus names
   com.acme.Foo
- method.  The name of method being called.  They look like
  ListName
- actual message pay load (we don't do anything with it currently)

And of course there are multiple buses (system and session).

Notes:
- Mediation is done on acquiring a service name (somewhat like bind of a network
  address), and sending of messages.  The sending of messages is done with a
  symmetric mediation, ie. the source is checked that it can send the message
  and the destination that it can receive the message.  So a single send may
  result in the creation of 2 audit messages.

- The patch does not provide any ability to configure so apparmor
  dbus mediation is on if you have apparmor enabled.  To disable set
  apparmor=0 as a kernel boot parameter

- I have rewritten and restructured the auditing path, so that there
  shouldn't be any extra allocations and copying.  It also is only
  constructed when an audit message is to be emitted.

- The auditd path is broken at the moment but I have not built against
  it.  So that isn't a problem atm.

- The code is faster and does less copying of buffers and fewer syscalls,
  not that this should really be a problem as dbus has quite enough
  overhead of its own, so our mediation should hopefully be minimal.
  With that said, when we move to the proper patch things will be faster
  as caching of state can be done removing some kernel round trips.

- I have fixed the issue with session and system bus, now they should
  work correctly if specified.

- There is a known problem with failing method calls from tasks that have
  already died or exited, currently we reject the message as the context
  the message came from can not be established.  Unfortunately network
  manager relies on this behavior, and breaks when we do this.  So for now,
  we toggle complain mode for these messages, so you get an "ALLOW" log for
  them.  There is no way to make them go away.  The log will also have
  serror/terror and info fields for these messages.

  Long term this will get fixed by socket labeling and get peersec in the
  kernel but I am just not there yet.

- send/receive Messages show up in pairs, with source and target switched.
  Unless one side of the pair is allowed, in which case the one that is
  allowed is not output.

- There is no way to force auditing of matches currently

- if you have apparmor libs in /usr/local/lib/  remove them, they will keep
  dbus from starting.

- Only the dbus operations acquire and method_call, and signal are handled
  correctly "method_return", "error", are not currently handled but logged.
  These are going to require more design as they often don't have anything
  more than the dbus unique destination set.
  eg.
    dest=":1.16"

- if something dies you should be able to reboot with apparmor=0 and dbus
  will disable trying to do apparmor mediation.

- the current patch does not like older kernels.  It will fail all
  permission requests.  We need to add a new state that detects apparmor
  is available but doesn't support dbus.

- dumping the exe for unconfined tasks would really help figure out what
  needs profiles.

- log messages missing the pid= field are from the dbus itself

- log messages missing the tpid= field are to the dbus itself


DBUS policy syntax

The policy rules are designed similar to the networking rules.  To allow all dbus
messages, acquiring of service names etc. you just need the rule

  dbus,

While the rule
  dbus system com.foo acquire,

Is very specific in stating that the profile is allow to acquire the com.foo
service name on the system bus.  The policy format currently supported is
as follows

['audit'] ['deny'] dbus ['system'|'session'] [['address=']<address>] ['path='<path>] ['interface='<interface>] ['method='<method>] [<perms>] ','
<perms> := <perm> | '(' (<perm> ','|[\w]) <perm> ')'
<perm> := r, w, rw, send, receive, acquire, bind, read, write

For the permissions
r maps to read which maps to receive,
w maps to write which maps to send,
bind maps to acquire


The ordering is currently important but in the future it could be more
flexible as most components are named if they are specified.  If any
component is left off a rule then it will match everything of that type.
ie.
  dbus com.foo,

will allow sending messages to com.foo, receiving messages from com.foo,
and acquiring the service name com.foo on both the session and system buses.

  dbus system com.foo w,

allows sending messages too com.foo on the system bus.  Which can also
be expressed as

  dbus system com.foo send,

Any single permission is allow to be specified by it self, but if more
than one permission is specified it must appear in a list similar to the
flags format.

  dbus system com.foo (send, receive),

The commas within the parenthesis are optional, plain whitespace delimitation
works just as well.  The only exception the paren rule for multiple permissions
is rw, which can be used outside of or inside of parens.

Note it is legal to specify
  dbus system com.foo (rw, send receive),

A few more examples of valid rules
  deny dbus system com.foo path="/foo /bar" interface=com.bar method=fred rw,

  dbus address=com.foo path=/foo/bar (send receive),

  dbus com.foo acquire,


Now that the basis of the current policy is out of the way we can not a couple
of things.
1. Current policy doesn't allow specifying a local and a remote, and I am not
   sure I can see a case where it makes sense to do so.  The address is mapped
   to both local and remote.
   ie.
     dbus com.foo  rw,

   means allow receiving messages from com.foo, and sending messages to com.foo

   Generally it would be good practice to split up dbus rules when addresses
   and or permissions are specified.  And we may consider enforcing such a
   rule.

     dbus,

   mapping to everything makes sense.  But the dbus com.foo case is a little
   confusing if you think about it and throwing bind/acquire into the mix
   just makes it worse.

2. acquire/bind only apply the the address= expression, which makes including
   it in rules with path and method information a little weird.  Again
   acquire should be used in a separate rule.

3. addresses, paths, interfaces and methods support apparmor regexs, so don't
   forget to escape special characters.

4. addresses, paths, interfaces, and methods can all be quoted.

5. The profile= flag is not currently supported, which means you can't specify
   the target profile of the communication.

  dbus profile=/foo/bar,   #only allow communicating of task confined by /foo/bar

  This is planned for just not implemented yet.




More information about the AppArmor mailing list