Thread (22 messages) 22 messages, 7 authors, 2011-10-20

Re: IP_TRANSPARENT requires CAP_NET_ADMIN - why?

flat view

From: Balazs Scheidler <hidden>
Date: 2011-09-02 08:50:27

Hi,

On Thu, 2011-09-01 at 14:25 -0700, Maciej Żenczykowski wrote:
quoted
I'm curious why transparent sockets [setsockopt(IP{,V6}_TRANSPARENT),
ie. inet_sk(sk)->transparent bit] require CAP_NET_ADMIN privileges.

Wouldn't CAP_NET_RAW be more appropriate?

Looks to me like CAP_NET_RAW is all about raw sockets.
Transparent sockets are dangerous because they effectively allow spoofing.
But this seems to be the same sort of thing that CAP_NET_RAW protects
against.

Is there something I'm missing?
Is there any reason why having CAP_NET_RAW privs shouldn't allow one
to set the transparent bit on a socket?

Would people be opposed to relaxing the check on setting sk->transparent
to be either CAP_NET_ADMIN or CAP_NET_RAW?
Well, the reason for choosing CAP_NET_ADMIN is that the original tproxy
functionality in Linux 2.2 required that cap, and we never questioned
it. Also, earlier the bits in the capability mask was a scarce resource
earlier. But see more info at the end of this email.
Why am I even interested?  I have a couple of apps (dns servers, web
servers, load balancers, web crawlers) that
don't require any special permissions except the ability to use any ip
as the source ip for a listening tcp, outgoing tcp, and/or udp socket.
For example machines may receive arbitrary traffic over a tunnel (with
absolutely any ip as the destination ip within the tunneled payload)
and need to respond to it, hence they need to be able to respond with
any ip as the source ip.  This can be achieved with combinations of
routing tricks and/or ip non local bind and/or ip_transparent.

The way I see it there are a couple possibilities.

a) Leave as is: IP{,V6}_TRANSPARENT requires CAP_NET_ADMIN

   This seems like the least desirable solution, we end up requiring a
much more powerful privilege then necessary.

b) Backward compatible: Make it require one of CAP_NET_ADMIN or CAP_NET_RAW

   Better, but kind of ugly in there being two permissions that allow this.

c) Not-backward compatible: Make it require CAP_NET_RAW instead of CAP_NET_ADMIN

   Better, in that a less powerful privilege is required, but *does*
break non-root software which uses CAP_NET_ADMIN to get TRANSPARENT
sockets.
   Also the gain isn't that great, in that we are still using a
privilege which is a little too powerful.

d) Add a new capability: Make it require CAP_NET_ADMIN or CAP_NET_TRANSPARENT

  Again backward compatible - ugly.

e) Add a new capability: Make it require CAP_NET_ADMIN or CAP_NET_RAW
or CAP_NET_TRANSPARENT

  Again backward compatible - ugly.  The reason for allowing
CAP_NET_RAW is that it effectively already allows this to be done with
raw sockets in a less useful way.  ie. AFAICT CAP_NET_TRANSPARENT is a
subset of CAP_NET_RAW

f) Add a new capability: Make it require CAP_NET_TRANSPARENT instead
of CAP_NET_ADMIN

  Not backward compatible, introduces a new capability, however, long
term this is probably the cleanest.

My personal vote is for (f).  I figure the number of non-root-apps
that have CAP_NET_ADMIN in order to get IP{,V6}_TRANSPARENT support is
very low, and they should be easy to fix to request
CAP_NET_TRANSPARENT instead.
I was a bit involved in a capability change earlier, in the syslog-ng
context. It is quite ugly, but doable.

For a new capability to work correctly the following changes must
trickle down to distributions:

  1) new kernel
  2) very recent glibc
  3) new libcap (both devel & runtime)
  4) patched applications (compiled against a new libcap)

If any of those is not yet patched, it won't work. Users tend to upgrade
the kernel and applications but rarely do so with the rest of the
userspace stack, e.g. libcap, which has caused some pain with syslog-ng.

The way that it was did for CAP_SYSLOG is that for a time CAP_SYSLOG
already worked, and the older cap CAP_SYS_ADMIN works too, but displays
an ugly oops-like kernel warning.

Certainly all of these can be worked around:

1) kernel

well, it's up to the user, but if the kernel is older than the one which
supports CAP_NET_TRANSPARENT, there's no issue.

2) glibc

The only way to detect if the kernel supports cap is to read the
capability bounding set, which uses a prctl() option that is defined by
a very new glibc (and kernel 2.6.25)

In syslog-ng, we had to define the value for PR_CAPBSET_READ in case it
wasn't defined.

3) libcap

The value for CAP_NET_TRANSPARENT is in the header file (e.g. devel
package), but that's not enough. We've seen distros, where the header
did contain the capability, but the runtime didn't know about the new
cap. I'm not sure why that happens, but it did on Fedora 15

https://bugzilla.balabit.com/show_bug.cgi?id=108#c24

The runtime needs to know about the new capability when transforming a
string representation to a bitset.

4) new apps

Well, the solution is not very easy to get right, and there's still some
problems with syslog-ng even after a couple of rounds. (see the end of
the quoted bugzilla ticket).

All this described to say that it is certainly doable, but requires
effort to get right and will definitely need to define a grace period
for which it is backward compatible. 

Somewhat less effort is needed if we reuse CAP_NET_RAW though, since
that is already in all kernels/libcap/glibc versions.

All that much said, I would vote for CAP_NET_RAW, and a grace period of
a couple of kernel releases, until the kernel displays a warning, like
it did with the CAP_SYSLOG case.

I'm a bit overwhelmed with stuff though, and would be happy if someone
else could prepare the necessary changes. But if someone does, I'd
recommend reading the CAP_SYSLOG related changes in kernel history to
avoid repeating the same mistakes.

-- 
Bazsi
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help