[apparmor] IPC syntax - again

John Johansen john.johansen at canonical.com
Sun Jun 30 10:07:38 UTC 2013


On 06/28/2013 04:49 PM, Seth Arnold wrote:
> Impressive email, thanks.
> 
> I can't begin to address all the open questions you raised, but we have
> to start somewhere, so here's my stab at what I felt was most important:
> 
> Pairing
> 
> You've very nearly convinced me that for the various forms of on-machine
> IPC pairing does not make a lot of sense and the automatic label mechanism
> is a better fit.
> 
Ha! I haven't convinced my self. That is I know we can do mediation based
off of treating it as a shared object, but at a cost of throwing away
some semantic information.

The question is whether this extra semantic information is worth the
complexity. For many forms of ipc some of the semantic information
is already useless.
  take dbus send, it is using a randomly assigned address, basically the
same as an unbound anonymous socket, but worse in that its equiv to just the
randomly assigned port number, as the rest of address would be the same
as its all machine local.

> But TCP and UDP feels like one place where we cannot compromise
> pairing. Many services offer vastly dissimilar services on different
> ports, even if one event loop in one profile handles all the sockets:
> 
> - Python Twisted makes it easy to set up a 'manhole' shell in a service
>   with full code-execution privileges; this is different from the services
>   it might offer to clients that wouldn't be wide-open code execution.
> 
>     network inet tcp subject { address=192.168.122.1 port=1337 }
>         peer { address=192.168.122.1/24 },

okay, but do we want to only accept connections from 192.168.122.1/24 to
192.168.122.1:1337 or would it be acceptable for communications from
192.168.122.1/24 on port 2000, if or service had a port open @ 2000.

That is security wise is it important to tie communications from
192.168.122.1/24 to the or services port of 1337
 
>     network inet tcp subject { address=0.0.0.0 port=80 }
>         peer { address=0.0.0.0 },
> 
> - Erlang connects nodes in a cluster over a socket that gives full
>   code-execution privileges, again separate from the services the Erlang
>   programs would offer to clients.
> 
ugh please don't tell me they are doing this on anything that isn't ipsec
or at least if they are not is there security value in the peer address
that is provided?

>     network inet tcp subject { port=4369 } peer { address=10.0.0.0/8 },
>     network inet tcp subject { port=465 },
> 
> - Administrators may configure web servers to provide different
>   privileges for data or control structures, and want to restrict access
>   to the more-privileged interface to a subset of network-connected
>   machines.
> 
okay, is MAC policy the correct place to do this?
>     network inet tcp subject { port=80 iface=eth0 }
>         peer ( address=192.168.1.111 },
>     network inet tcp subject { port=80 iface=wlan0 },
> 
> - A hypothetical information pump / proxy service -- antivirus, data
>   retention compliance servers, privacy scrubber.
> 
>     profile internal_face {
>     network inet tcp subject { iface=eth0 address=192.168.1.1 port=80 }
>         peer { address=192.168.1.1/24 }.
>     network inet tcp subject { iface=lo0 address=127.0.0.1 port=55555 }
>         peer { address=127.0.0.1 port=55556 }
>     }
> 
>     profile external_face {
>     network inet tcp subject { iface=eth1 address=10.0.0.1 }
>         peer { address=10.0.0.1/24 }.
>     network inet tcp subject { iface=lo0 address=127.0.0.1 port=55556 }
>         peer { address=127.0.0.1 port=55555 }
>     }
> 
> I've been thinking about it a bit though; I know we've always wanted to
> just write addresses right in profiles like this, but the actual work
> to compile down to secmark-capable labels requires full policy compiles.
> 
yes

> We've talked about ways around a full policy compile, but support partial
> policy reloads with these mechanisms always breaks my brain.
> 
its not that bad really

> Can we instead treat tcp and udp (and sctp and ..) as labeled shared
> objects, just like everything else you've proposed, but with the caveat
> that userspace is responsible for putting together the labels?
> 
err userspace? As in iptable rules? Yes as a first pass. Do we want to
split policy out in such a way? NO!

It is a very big mistake to divide our policy between different config
files. We have tried hard to avoid this, and the small reduction in
implementation cost is not worth the increased cost of managing a
split policy.

Again, for secmark we will allow manually writing rules, after all anything
we generate has to be a valid set of iptable rules. But as much as possible
lets keep it automated.

> We can keep the "easy" things entirely in the profiles: bind to ports
> and addresses, listen, accept, connect. All these can be done without
> full policy compiles. These can provide useful security even without
> the extra work to support the pairing that I'm about to suggest.
>
So be careful here part of the problem and why we need to deal with things
at the kernel level is that we don't want to just out right reject things
post accept. We need to be able to determine whether a connection can
be accepted at the interrupt level without a task context.

Interestingly enough, using compound labels we can do this without needing
to use the secmark. That doesn't mean we want want to use it just that
we can do certain things that previously we would have needed a full
policy compile for.

I think the connsecmark in particular might still be very useful for things
like ftp. Btw please provide some nice examples of how you see policy
working with ftp, since its such a fun protocol to deal with.

> But if an admin wants to support the pairing, we punt directly to secmark
> and either let users write raw iptables commands to mark packets or extend
> ufw to know how to add marks to packets. It'll take some thinking to come
> up with the best way to get this, but I'm envisioning something like this:
> 
Again if/when we use secmark manually setting labeling will become possible.
However I do not want to encourage it as a default behavior. When it comes
to implementation vs. policy management complexity I will almost always
choose implementation complexity so our users don't have to deal with it.

Policy is already too hard
> Twisted:
> 
> ufw allow from 192.168.122.1 \
>     to 192.168.122.1 port 1337 proto tcp mark twisted_manhole
> ufw allow to port 80 proto tcp mark twisted_service
> 
> profile twisted_server {
>   network inet tcp (bind, listen, accept) 192.168.122.1 port 1337,
>   network inet tcp (bind, listen, accept) port 80,
>   network inet tcp label=twisted_manhole,
>   network inet tcp label=twisted_service,
> }
> 
> 
> Erlang:
> 
> ufw allow from 10.0.0.0/8 to port 4369 proto tcp mark erlang_cluster
> ufw allow to port 465 proto tcp mark erlang_mail
> 
> profile erlang {
>   network inet tcp port 4369,
>   network inet tcp (bind, listen, accept) port 465,
>   network inet tcp label=erlang_cluster,
>   network inet tcp label=erlang_mail,
> }
> 
> 
> Webserver:
> 
> ufw allow in on eth0 from 192.168.1.111 to port 80 proto tcp mark web_priv
> ufw allow in on wlan0 to port 80 proto tcp mark web_pub
> 
> profile www {
>   network inet tcp (bind, listen, accept) port 80,
>   network inet tcp label=web_priv,
>   network inet tcp label=web_pub,
> }
> 
> 
> Complicated MAC'd proxy:
> 
> ufw allow in on eth0 from 192.168.1.1/24 \
>     to 192.168.1.1 proto tcp mark proxy_in
> ufw allow in on lo0 from 127.0.0.1 port 55555 \
>     to 127.0.0.1 port 55556 proto tcp mark proxy_middle
> ufw allow out on eth1 from 10.0.0.1 \
>     to 10.0.0.1/24 proto tcp mark proxy_out
> 
> profile proxy {
>   network inet tcp (bind, listen, accept) port 80,
>   network inet tcp (connect) 10.0.0.1/24,
>   network inet tcp label=proxy_in,
>   network inet tcp label=proxy_out,
>   network inet tcp label=proxy_middle,
> }
> 
> 
> I might not have the details exactly right -- I'm nearly confident of
> that -- but I hope this sketch gives an idea of how we can use ufw to
> provide a convenient place to add secmark labels that we then use in
> AppArmor profiles.
> 
> It's more moving pieces -- and we probably can't give decent error
> messages in the case of spelling mistakes, probably can't "learn" these,
> and certainly wouldn't ship any of these pairing-by-labels -- but it
> does let us provide the functionality that more advanced deployments
> will want.
> 
> We don't have to use ufw -- standard iptables --selctx can also work --
> but ufw is easier for me to understand. ufw can also provide a
> convenient location for name <-> number mappings, or perhaps a
> convenient interface for managing the mappings.
> 
Look I like ufw, but as an upstream project we need to look at the
solution that is widely applicable to the distributions that ship apparmor
so iptables seems the better target from that perspective. I am not saying
don't support ufw just that iptables would need to be supported.

> This also gives us a possibility for a staged deployment: we can get the
> "simple" stuff done first -- the bind, listen, accept, connect, sendmsg?,
> recvmsg?, that can be decided simply from the contents of a profile -- 
> 
Staged deployment has always been planned. We just can't get everything
done in the time frame we have. We are just trying to plan to make sure
what we do ship is consistent with where we are going





More information about the AppArmor mailing list