[Apparmor-dev] Network definitions in profile

John Johansen jjohansen at suse.de
Fri Nov 30 17:52:56 MST 2007


On Fri, Nov 30, 2007 at 02:40:11PM +0200, Markku Savela wrote:
> A while back, there was a proposal about armoring the access to the
> network resources. I would like to propose a simpler approach for
> initial implementation and leave the "complete" solution for future
> expansion and specification.
> 
Well I am all for an incremental approach that takes steps towards
the final goal

 > snip <

> -----------------------------------------------------------
> 
> I would just implement a simpl approach, which would address the
> immediate needs:
> 
>  - allow profile to say: application can only bind specific address/port
> 
>  - allow profile to say: application can only connect specified address/port
> 
>  - no changes to the current LSM hooks in kernel
> 
>  - not dependent on any iptables features or framework
> 
this certainly does make the implementation easier

> The current socket related LSM hooks relevant to this proposal (please
> correct me, if you notice I have made any mistakes below) are:
> 
> socket_connect
> 
>   Socket connect lsm hook does not usually have information on the
>   source address (selected later). Source is unspecified, unless bind
>   has been used with specific address.
> 
>   => Connect lsm hook can verify remote address and port against the
>   profile.
> 
yep

>   => If connect profile required a specific source port or address
>   (like loopback), the application must use the appropriate bind to
>   pass the apparmor profile.
> 
yes, any source port is going to get mapped to what has been bound

> socket_bind
> 
>   Socket bind lsm does not have the remote address.
> 
>   => Bind lsm hook can only verify the local address part of the
>   profile.
> 
yep, which is sufficient for checking if creation is allowed and
labeling it.

> socket_accept
> 
>   Socket accept is useless -- it does not know anything about the
>   incoming connection yet (in addition to what is known from bind
>   already).
> 
>   => Only use for this in profile would be of little value: allow/deny
>   accept operation in general.
> 
sadly, yes

> socket_listen
> 
>   Socket listen is useless -- it does not know anything about the
>   connections and addresses (in addition to what is known from bind
>   already)
> 
>   => Only use for this in profile would be of little value: allow/deny
>   listen operation in general (or specified bind address).
> 
yep

> socket_recvmsg
> 
>   Socket recvmsg is useless -- it only indicates application is ready
>   to receive data (datagram).
> 
>   => datagram sockets would have bind information available, connected
>   sockects would have both addresses.
> 
hmm, not useless but not important to what you propose.

> socket_sendmsg
> 
>   Socket sendmsg has to-address in msghdr, if application is using
>   unconnected datagram socket and specified the address.
> 
>   => The "connect" address can be verified by the LSM hook.
> 
sounds right

> My first proposal is to simplify and modify the previously proposed
> syntax to cover only the simple case of protecting the "bind",
> "connect" and (datagram)"sendmsg", and leave the remaining issues for
> future expansion. I could implement this simple "phase 1" as a
> practise job in getting to know the apparmor and LSM.
> 
> My proposed simplified syntax is (first draft):
> 
> ----------------------------------------------------------------
> rule        = "network" [ [ <domain> ] [ <type> ] [ <protocol> ]
>                           [ <proto_expr> ] ] ","
> domain      = "inet" | "ax25" | "ipx" | "appletalk" | "netrom" |
>               "bridge" | "atmpvc" | "x25" | "inet6" | "rose" |
>               "netbeui" | "security" | "key" | "packet" | "ash" |
>               "econet" | "atmsvc" | "sna" | "irda" | "pppox" |
>               "wanpipe" | "bluetooth"
>     *note: "unix", "local" and "netlink" are not allowed
> type        = "stream" | "dgram" | "seqpacket" | "rdm" | "raw" | "packet" |
>               "dccp"
> 
> protocol    = "tcp" | "udp" | "icmp" | "ftp" | "icmp6" | "ip" DIGIT(1,3) | ...
> 
> proto_expr  = <ip_action> | 
> 
> ip_action     = "bind" <ip_expr> | "connect" <ip_expr>
> 
> ip_expr	    = <ip_addr> [ "/" 1*2DIGIT ] ["#" <port_expr>]
> 
> ip_addr	    = <ipv4_addr> | <ipv6_addr>
> 
> ipv4_addr   = DIGIT{1,3} ("." DIGIT{1,3}){3,3}
> 
> ipv6_addr   = <hexseq> | <hexseq> "::" [ <hexseq> ] | "::" [ <hexseq> ]
> 
> hexseq      = hex4 ( ":" hex4)*
> hex4        = HEXDIG{1,4}
> 
> port_expr   = DIGIT{1,5} [ "-" DIGIT{1,5} ]
> -------------------------------------------------------------------
> 
> Some examples:
> 
> 1) Allow (webserver) application to bind only tcp port 80 (either IPv4 or IPv6)
> 
>   network tcp bind #80,
> 
>   (Note, without "connect", webserver is not able to activate own connections)
> 
> 2) Webserver to serve only local the loopback
> 
>   network tcp bind ::1#80
>   network tcp bind 127.0.0.0/8#80
> 
> 3) Allow  application to perform DNS queries (either over IPv4 or IPv6)
> 
>   network udp connect #53,
>   network tcp connect #53,
> 
>   (This assumes that "connect" target is also checked on sendmsg LSM
>   for unconnected sockets). If you have local named running, one could
>   even limit the above as
> 
>   network udp connect 127.0.0.0/8#80
>   network tcp connect 127.0.0.0/8#80
>   network udp connect ::1#80
>   network tcp connect ::1#80
> 
> 4) Allow application only to talk to port 80
> 
>   network tcp connect #80
> 
Hrmm, I am not fond of using the bind keyword (though I am more than willing
to be convinced otherwise).  In the older design the binding information is
there it is just implicit.  What I would like to see change from the older
design is from, to becoming "local" and "remote" so it is easy to determine
what is meant.  And then a subset of the full proposal could be used
to obtain the binding information.

So reusing your examples from above

eg.
1) Allow (webserver) application to bind to port 80 and accept connections
   (either IPv4 or IPv6).  Note this does not allow webserve to connect.

  network tcp accept local #80,

2) Webserver to ser only local loopback

  network tcp accept local ::1#80,
  network tcp accept 127.0.0.0/8#80,

3) Allow application to perform DNS queries (eith over IPv4 or IPv6)

  network udp connect to #53,
  network tcp connect to #53,

4) Allow applications to only talk to port 80

  network tcp connect to #80,


This makes the bind information implicit as part of the rules still leaves
us open to do rules like,

  network tcp connect to #80 from #1025-65k,

for connections we can figure out the bind source allowed and have
the pairing without relying on netfilter.

For accepting connections we should just be able to forbid specifying
the  from/remote end of the specification.  And extract the bind information
from the to/local portion.

> 
> Open issues:
> 
> - how is this information stored in binary profiles
> 
in some form of fast data structure

> - could the algorithms used in file path matching utilized somehow
>   (e.g. can the network profiles be turned into file path like
>   constructs that can be processed and matched with existing functions
>   within apparmor kernel module).
> 
yes.  It requires some user side work, a lot of which I have been doing
anyways to make the dfa code more general.  The data could be represented
as an ordered string but it would be even better to treat it in a binary
fashion so that the kernel doesn't need to build up a string to match
against.

I can handle extending both the kernel and user side to meet your needs,
if this is the way we want to go.  I can also handle the user side parsing
if you would like.

> - how to allow the future extension, without need to rewrite this
>   implementation totally.
> 
This is one of the reasons I counter proposed against using bind
directly.  If we can start out with just allowing accept to
specify the local portion of the address, and connect to specify the
remote portion of the address, the utility should be similar.

Then we can incrementally add the ability to specify a local address
with connect, and then eventually add the packet labeling necessary
to handle remote address on accepts, and conntracking and other
exotic stuff.

But again I am more than willing to be convinced I am wrong, I really
want to see this go forward, and I don't want syntax to stop it.
In fact for prototyping purposes I don't see the two as being different
kernel side, so syntax could be resolved post implementation.

thanks
john
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 194 bytes
Desc: not available
Url : http://forge.novell.com/pipermail/apparmor-dev/attachments/20071130/e581dfe7/attachment.pgp


More information about the Apparmor-dev mailing list