Re: Secure-linux and standard kernel

James H. Cloos Jr. (cloos@jhcloos.com)
26 Jun 1998 11:39:12 -0500


>>>>> "Albert" == Albert D Cahalan <acahalan@cs.uml.edu> writes:

Albert> ELF-only is good enough for Linux 2.2. It is better than was
Albert> expected. Perl scripts will have to wait for Linux 2.4, with
Albert> filesystem support.

If suidperl is sufficiently trusted, all Perl scripts need to do is
call capget(2) and capset(2) to drop the capabilities they do not
need. Eg:

===========================================================================
#!/usr/bin/perl

sub BEGIN {
# The following block should be a require 'syscall.ph' but that will
# only work if the installed glibc and perl were built against a 2.1
# kernel, the following will work on any current distrib so long as a
# recent 2.1 kernel is running.

eval 'sub __NR_capget () {184;}' unless defined(&__NR_capget);
eval 'sub __NR_capset () {185;}' unless defined(&__NR_capset);
unless(defined(&SYS_capget)) {
sub SYS_capget () { &__NR_capget;}
}
unless(defined(&SYS_capset)) {
sub SYS_capset () { &__NR_capset;}
}

# You will need to run h2ph to make this if perl
# was compiled vs a 2.0 kernel tree...
require 'linux/capability.ph';

$cap_header = pack("Li", 0x19980330, $$);
$cap_effective = pack("L", 0);
$cap_permtted = pack("L", 0);
$cap_inheritable = pack("L", 0);
$cap_data = pack("PPP", $cap_effective, $cap_permtted, $cap_inheritable);

syscall(&SYS_capget, $cap_header, $cap_data)
or die "Cannot get capabilities flags";

($cap_version, $cap_pid) = unpack("Li",$cap_header);

($cap_effective, $cap_permtted, $cap_inheritable) = unpack("PPP",$cap_data);

$cap_effective = $cap_inheritable =
pack("L", (unpack("L",$cap_permtted) & (1<<CAP_NET_BIND_SERVICE)))

$cap_header = pack("Li", $cap_version, $cap_pid);
$cap_data = pack("PPP", $cap_effective, $cap_permtted, $cap_inheritable);

syscall(&SYS_capset, $cap_header, $cap_data)
or die "Cannot set capabilities flags";
}

# Now go on to do your server....
===========================================================================

The above is only minimally tested. Ie, I've got a server that can
bind, etc but cannot eg write to a file in /root/. (I'm sure someone
will correct any errors. At the very least there should be checks on
whether the $cap_permitted returned by capget(2) is NULL; if so I think
it should be treated as though it were pack("L",~0). I think. But it
is time to crash now, so don't take my word for it. :)

Were all that it a module, one could have something like:

use Capabilities qw(CAP_NET_BIND_SERVICE CAP_SYS_TIME);

as the fisrt line in a server to allow it to bind to low ports and to
chnage the system time. (eg, for a ntpd type server.) In any case, a
proper Capabilities.pm, invoked before anything else, will be as
secure as suidperl(1) is. Of course, you could also embed 'use
capabilities' into the binary, a la 'use strict', 'use integer', etc.

-JimC

-- 
James H. Cloos, Jr.
<cloos@jhcloos.com>

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