On Fri Jul 05 2002, Brian Hatch (vuln-dev_at_ifokr.org) wrote:
> POSIX capabilities do compartmentalize permissions to 'does this
> process have capability X' instead of 'is this process running
> as uid/euid root'. However in the Linux kernel, the capabilities
> calls all look like this:
>
> if ( port < 1024 && !capable(CAP_BIND_NET_SERVICE) ) {
> /* complain */
> }
>
> But the capable call is defined as:
>
> int capable(int capability) {
> if ( euid==0 || uid==0 ) return 1
> }
>
> (That's all pseudo code, not the actual code.)
>
> So although capabilites are built into the kernel, the base check
> is still just using {e}uid==0.
>
Well actually the capable call (in kernel 2.2.21 at any rate) is defined
in sched.h thus:
extern inline int capable(int cap)
{
#if 1 /* ok now */
if (cap_raised(current->cap_effective, cap))
#else
if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0)
#endif
{
current->flags |= PF_SUPERPRIV;
return 1;
}
return 0;
}
... so the code that is actually used is cap_raised(), which is defined in
capability.h as:
#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag))
ie, the cap_effective mask of the current task structure is checked against
the requested capability. The capability checking code is all good to go -
it only requires a creative way of selectively setting cap_effective to work.
I think rather than a proliferation of filesystem "setcap" bits for
executables, it's likely that a program would remain setuid root, but
drop all unneeded capabilities as it's first task when run (ie, ping would
drop all capabilities except CAP_NET_RAW).
- Kevin.
Received on Jul 06 2002