[Apparmor-dev] IPC Mediation

Crispin Cowan crispin at novell.com
Mon Apr 9 03:53:09 MDT 2007


Mediation of IPC has been a long-standing goal, going back at least as
far as the debate during the 2006 attempt to upstream the AppArmor
kernel module. We have recently been working on a design for IPC
mediation in the Portland lab, with this result.

The AppArmor design philosophy is that when ever you mediate anything,
you do it in the native terms of the resource being mediated. But when
you consider the list of all possible kinds of IPC in Linux, you
discover that there are a lot :)

    * SYSV
          o shared memory (shmctl)
          o message queues (msgctl)
          o semaphore (semctl)
    * POSIX
          o shared memory (shm_open)
          o message queues (mq_open)
          o semaphores (sem_init)
    * Pipes
          o named pipes (mknod)
          o anonymous pipes (pipe)
    * Sockets
          o local
                + UNIX anonymous (socketpair)
                + UNIX named (unix(7))
                + netlink (netlink(7), 16 more subprotocols)
          o Local and remote
                + IPv4, also raw sockets (raw(7))
                + IPv6
                + IPX
                + x25 (remote only?)
                + ATM (remote only?)
                + Appletalk
                + raw packets (packet(7))
    * Futexes (futex(2))
    * signals (kill(2))
    * realtime signals

This is too many different kinds of operations to treat each one in a
totally native way; the profile language would become far too complex,
violating the AppArmor fondness for the KISS principle :)

So we can simplify this into these equivalence classes of IPCs:

    * Looks like a pipe or a  file descriptor
          o Mediation: control who can connect to the pipe by labeling
            the pipe with the name of a profile
                + Do this by 'tainting' the pipe with the profile names
                  of every process that touches it
          o includes
                + all the socket stuff
                + all the local and remote stuff
                      # IPv4, IPv6, IPX, and Appletalk
          o issues
                + pipes can persist long past the lifespan of the
                  creating process, or even the creating profile
                + named pipes are not a problem; we handle the with
                  existing name based access controls
                + taint the thing (pipe, semaphore, etc) with the name
                  of every profile that touches it
                      # each profile includes a list of "may chat with"
                        <list of profile names> and this is checked
                        against the history of profiles that have
                        previously touched the pipe/thing
                      # re-validating the taint chain on profile reload
                        is problematic, but doable
                            * stipulate that attempts to restrict a
                              running process with a tighter profile
                              cannot be assured
    * Interrupts
          o Signals, RT signals
          o Mediation:
                + in each profile, write "may interrupt " followed by
                  the name of a profile
                + have a special name "unconfined" to allow a confined
                  process to interrupt an unconfined process
    * Shared memory: anything that shares state
          o shared memory
          o maybe semaphores
          o consensus: use file descriptor tainting model
    * Semaphores: may be its own abstraction
          o POSIX semaphores
          o futexes
          o consensus: make like shared memory, use tainting model

There are several "maybe"s in there, and the consensus in lab discussion
was to minimize the number of different kinds of IPC mediation, so we
would consider shared memory and semaphores to be the same thing, and to
use the pipe/file descriptor tainting model for shared memory.

The bottom line is that IPC profiles would look like this:

  /bin/foo {
    share_mem /usr/bin/firefox r,        # /bin/foo can share memory with /usr/bin/firefox for read only
    share_mem /usr/bin/apache rwm,       # can read, map, and write to the shared memory with apache
    signal /bin/trusty (hup, chld),      # can signal to a process confined by profile named /bin/trusty
                                         # and the only signals that can be sent are hup and chld
    signal /** (hup, chld),              # can signal to any confined process, but only hup and chld
    signal P:/usr/bin/magic (hup, chld), # any process (confined or unconfined) running binary /usr/bin/magic
    signal P:/** (hup, chld),            # any process (confined or unconfined)
    signal {/bin/true,/bin/false} (*),   # can send any signal to either /bin/true or /bin/false
    share_fd /home/sarnold/bin/ugly rw,  # can share pipes & file descriptors with /home/sarnold/bin/ugly
                                         # and can read and write to the thing
  }

Unlike the rlimit issue, I really want IPC to be totally learnable: you
should be able to reasonably construct IPC policy by just running the
applications in complain mode and then using logprof/genprof to turn the
events into policy. The above events are sufficiently similar to the
file events that it should not be wrenching: each specifies an object
name that can be globbed (just like file access) and a set of operations
that accumulate bits (r, w, and m, or a bit vector of signals) just like
file access accumulates r, w, and x.

Note that the object name can be either the name of a profile, or the
name of an executable. This is because we want to control what a
confined process can do to *any* other process, including unconfined
processes.

Does this sound good to people?

Crispin

-- 
Crispin Cowan, Ph.D.               http://crispincowan.com/~crispin/
Director of Software Engineering   http://novell.com
AppArmor Training at CanSec West   http://cansecwest.com/dojoapparmor.html




More information about the Apparmor-dev mailing list