Re: Capabilities

Winfried Truemper (winni@xpilot.org)
Mon, 29 Jun 1998 02:04:10 +0200 (CEST)


On Sat, 27 Jun 1998, Andrew Morgan wrote:

> > execcap CAP_NET_BIND_SERVICE su named /usr/sbin/named
>
> As it stands, with no filesystem support for capabilities, you cannot
> do this.

As you suggested, I played around with a newer kernel and thought this
would help:

execcap "CAP_NET_BIND_SERVICE+i CAP_SETUID+i CAP_SETGID+i' \
/bin/su nobody -c '\
/sbin/execcap "CAP_NET_BIND_SERVICE+i CAP_SETUID-i CAP_SETGID-i" \
sleep 1000 &'

The first execcap should remove all capabilities except the specified
ones and a second accept removes the the setuid() and setgid() features
before executing that evil sleep.
Then I read kernel/sys.c and learned that capabilities get cleared
via cap_emulate_setxuid (which gets executed somewhere in su). Yes,
this is surely needed as "0" has become meaningless with regard to
privileges (it is not enough to change UID to "clear" privileges any
more).

I'm no set*id expert, but it would surely be convinient to have a tool
which combines su and execcaps so one can pass privileges to another
UID without filesystem support. It allows people operating their named
from a floppy with with romfs (in general: with a non-ext2 filesystem)
to have capabilities.

I suggest a hint about the rather flexible command line parsing of execcap
(or libcap, to be more precise): it accepts a space seperated list of
entries, consisting of a capability name and a modifier to add (+),
revoke (-) or set (=) the capability.

> Thus, named (here, I use sleep) inherits an interesting state:
>
> * it is run as root (it is "only" able to manipulate files
> owned by the root user).

Also interesting is the state it puts ordinary users in:

winni> /sbin/execcap "CAP_SETUID+i CAP_SETGID=i" /bin/bash
winni> echo $$
255
winni> /sbin/getpcaps 255
cabilities for `255': = cap_setgid,cap_setuid+i

So I wrote a small C script to "exploit" the capabilities to "change" the
*ID:

#include <unistd.h>
int main () {
if (setuid(0)) printf("setuid failed\n");
}

and executed it in the above environment (expecting it to succeed). But it
failed and I was becalmed somehow. I had a closer look to the output of
"getpcaps". Obviously, there is a slight difference between "root" and me:

root> getpcaps 82
Capabilities for `82': =eip cap_setpcap-eip
winni> /sbin/getpcaps 83
Capabilities for `83': =i cap_setpcap-i

Ah, the ep is missing. I read the documentation linux-privs.txt again and
came to the conclusion that the inheritable set works like a filter I can
apply to the capabilities of all my children. So it is secure for ordinary
users to own this filter-feature.
It would have been something different if I could permit child-tasks to
raise (e) or to grant them (p) with execcap.

> You could implement this with 10 extra bits, but it does not scale
> well: how would you enforce the ability to bind to two and only two
> ports below 1024? Or three? ...

I don't see the problem here. Can't I just do CAP_NET_PORT_1+i
CAP_NET_PORT_2+i and CAP_NET_PORT_3+i?

> To alleviate the latter concern, we could place the named process in a
> chroot cell and avoid having any files there owned by root. (Make them
> all owned by 'bin' or some other non-interactive user).

Yes, "named" surely belongs into a chrooted environment, having
capabilities or not.

> Limiting access to individual ports, from exec() is probably better
> handled with port access control lists...

Thanks for that clear statement.

But then again, wouldn't that apply to even more capabilities? As long as
there is a 1:1 relation between the capability and the userland-software,
everthing should be fine. Example: insmod gets the capability
CAP_LINUX_INSMOD and so far, no other tool should have a need for it .
But for CAP_SETUID, which is not associated with a fixed utitlity, one
maybe wants to restrict the capability to "setuid to UIDs above 100 only".
Maybe there is a general solution for ACL-enhanced capabilities?

> Since I have not followed this project, if I were you, I would follow up
> on the comment in linux/Documentation/ioctl-number.txt (search for 'Port
> ACL').

Indeed, I wrote some wrapper for PACL two weeks ago. It accepts a
human-readable configuration file (port_acl.cfg) of the following
form:
[*]
tcp 1024-65535 allow
udp 1024-65535 allow
tcp 0-1023 deny
udp 0-1023 deny

[root]
tcp 0-65535 allow
udp 0-65535 allow

[tlewis]
tcp domain allow
udp domain allow

But I couldn't get pacladmin.c to compile, after all I'm no C programmer.
The associated shell-wrapper is available from
ftp://ftp.guug.de/pub/members/truemper/port_acl-contrib.tgz. The
configuration file is self-documenting. The author did not yet
respond to me, so I post the pointer here, too.

Regards
-Winfried

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu