diff --git a/tests/regression/apparmor/environ.sh b/tests/regression/apparmor/environ.sh index 2049882da..25938d891 100644 --- a/tests/regression/apparmor/environ.sh +++ b/tests/regression/apparmor/environ.sh @@ -61,11 +61,11 @@ genprofile ${helper_sh}:Ux runchecktest "ENVIRON (shell script): Ux & regular env" pass ${helper_sh} FOO=BAR runchecktest "ENVIRON (shell script): Ux & sensitive env" fail ${helper_sh} LD_LIBRARY_PATH=. -genprofile ${helper_sh}:px -- image=${helper_sh} /bin/bash:rix "/lib*/lib*:mr" +genprofile ${helper_sh}:px -- image=${helper_sh} runchecktest "ENVIRON (shell script): px & regular env" pass ${helper_sh} FOO=BAR runchecktest "ENVIRON (shell script): px & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=. -genprofile ${helper_sh}:Px -- image=${helper_sh} /bin/bash:rix "/lib*/lib*:mr" +genprofile ${helper_sh}:Px -- image=${helper_sh} runchecktest "ENVIRON (shell script): Px & regular env" pass ${helper_sh} FOO=BAR runchecktest "ENVIRON (shell script): Px & sensitive env" fail ${helper_sh} LD_LIBRARY_PATH=. @@ -73,7 +73,7 @@ genprofile ${helper_sh}:rix /bin/bash:rix "/lib*/lib*:mr" runchecktest "ENVIRON (shell script): ix & regular env" pass ${helper_sh} FOO=BAR runchecktest "ENVIRON (shell script): ix & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=. -genprofile image=${helper_sh} /bin/bash:rix "/lib*/lib*:mr" +genprofile image=${helper_sh} runchecktest "ENVIRON (shell script): unconfined --> confined & regular env" pass ${helper_sh} FOO=BAR runchecktest "ENVIRON (shell script): unconfined --> confined & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=. diff --git a/tests/regression/apparmor/mkprofile.pl b/tests/regression/apparmor/mkprofile.pl index c7f81fe19..15b153231 100755 --- a/tests/regression/apparmor/mkprofile.pl +++ b/tests/regression/apparmor/mkprofile.pl @@ -9,9 +9,11 @@ my $__VERSION__=$0; use strict; use Getopt::Long; +use Cwd 'realpath'; my $help = ''; my $nowarn = ''; +my $nodefault; my $escape = ''; my %output_rules; my $hat = "__no_hat"; @@ -21,6 +23,7 @@ GetOptions( 'escape|E' => \$escape, 'nowarn' => \$nowarn, 'help|h' => \$help, + 'nodefault|N' => \$nodefault, ); sub usage { @@ -28,12 +31,108 @@ sub usage { print STDERR "Usage $0 [--nowarn|--escape] execname [rules]\n"; print STDERR " $0 --help\n"; print STDERR " nowarn: don't warn if execname does not exist\n"; + print STDERR " nodefault: don't include default rules/ldd output\n"; print STDERR " escape: escape stuff that would be treated as regexs\n"; print STDERR " help: print this message\n"; } &usage && exit 0 if ($help || @ARGV < 1); +sub head ($) { + my $file = shift; + + my $first = ""; + if (open(FILE, $file)) { + $first = ; + close(FILE); + } + + return $first; +} + +sub get_output ($@) { + my ($program, @args) = @_; + + my $ret = -1; + + my $pid; + my @output; + + if (-x $program) { + $pid = open(KID_TO_READ, "-|"); + unless (defined $pid) { + die "can't fork: $!"; + } + + if ($pid) { + while () { + chomp; + push @output, $_; + } + close(KID_TO_READ); + $ret = $?; + } else { + ($>, $)) = ($<, $(); + open(STDERR, ">&STDOUT") + || die "can't dup stdout to stderr"; + exec($program, @args) || die "can't exec program: $!"; + + # NOTREACHED + } + } + + return ($ret, @output); +} + +sub gen_default_rules() { + gen_file("/etc/ld.so.cache:r"); + + # give every profile access to change_hat + gen_file("/proc/*/attr/current:w"); + + # give every profile access to /dev/urandom (propolice, etc.) + gen_file("/dev/urandom:r"); +} + +sub gen_elf_binary($) { + my $bin = shift; + + my ($ret, @ldd) = get_output("/usr/bin/ldd", $bin); + if ($ret == 0) { + for my $line (@ldd) { + last if $line =~ /not a dynamic executable/; + last if $line =~ /cannot read header/; + last if $line =~ /statically linked/; + + # avoid new kernel 2.6 poo + next if $line =~ /linux-(gate|vdso(32|64)).so/; + + if ($line =~ /^\s*\S+ => (\/\S+)/) { + # shared libraries + gen_file(realpath($1) . ":mr") + } elsif ($line =~ /^\s*(\/\S+)/) { + # match loader lines like "/lib64/ld-linux-x86-64.so.2 (0x00007fbb46999000)" + gen_file(realpath($1) . ":rix") + } + } + } +} + +sub gen_binary($) { + my $bin = shift; + + gen_file("$bin:r"); + + my $hashbang = head($bin); + if ($hashbang && $hashbang =~ /^#!\s*(\S+)/) { + my $interpreter = $1; + gen_file("$interpreter:rix"); + gen_elf_binary($interpreter); + } else { + gen_elf_binary($bin) + } +} + sub gen_netdomain($) { my $rule = shift; # only split on single ':'s @@ -103,8 +202,10 @@ sub gen_hat($) { my $bin = shift @ARGV; !(-e $bin || $nowarn) && print STDERR "Warning: execname '$bin': no such file or directory\n"; -# give every profile/hat access to change_hat -gen_file("/proc/*/attr/current:w"); +unless ($nodefault) { + gen_default_rules(); + gen_binary($bin); +} for my $rule (@ARGV) { #($fn, @rules) = split (/:/, $rule); diff --git a/tests/regression/apparmor/prologue.inc b/tests/regression/apparmor/prologue.inc index adde4681c..956c3c0c4 100755 --- a/tests/regression/apparmor/prologue.inc +++ b/tests/regression/apparmor/prologue.inc @@ -85,102 +85,6 @@ genrunscript() fi } -resolve_symlink() -{ - if [ -z "${__NO_TRAP_ERR}" ] - then - trap "error_handler" ERR - fi - - local link linkdir targetdir targetname - - link=$1 - - while [ -h ${link} ] - do - if [ -x /usr/bin/readlink ] ; then - target=$(/usr/bin/readlink -f ${link}) - elif [ -x /bin/readlink ] ; then - target=$(/bin/readlink -f ${link}) - else - # I'm sure there's a more perlish way to do this - target=$( perl -e "printf (\"%s\n\", readlink(\"${link}\"));") - #target=$( perl -e "if (\$foo = readlink(\"${link}\")){ \ - # printf (\"%s\n\", \$foo) \ - # } else { \ - # print \"${link}\n\"; \ - # };") - fi - case "${target}" in - /*) link=${target} - ;; - *) linkdir=$(dirname ${link}) - targetdir=$(dirname ${target}) - targetname=$(basename ${target}) - linkdir=$(cd ${linkdir}/${targetdir} ; pwd) - link=${linkdir}/${targetname} - ;; - esac - - done - - if [ -e ${link} ] - then - echo ${link} - return 0 - else - echo "Could not resolve '$link'" >&2 - return 1 - fi -} - -resolve_libs() -{ - if [ -z "${__NO_TRAP_ERR}" ] - then - trap "error_handler" ERR - fi - - local exec mode libpath libs - # global dynlibs - - exec=$1 - - if [ ! -x $1 ] - then - fatalerror "invalid test executable $test" - fi - - # Suck. SuSE's ldd has a line "linux-gate.so.1 => (0xffffe000)" - # Red Hat's ldd has "/lib/ld-linux.so.2 (0x007b1000)" - # good ${DIETY}, what gross kludgage. - libs=$(ldd $exec | egrep -v "linux-(vdso(32|64)?|gate).so.1" | sed 's~^.*=> \(/.*\) (.*$~\1~' | awk '{print $1}') - - dynlibs="/etc/ld.so.cache:r" - - # bleah, this is cheeseball. on systems with a stackguard - # compiler, we also need access to /dev/urandom - for i in $libs /dev/urandom - do - mode=rm - # resolve possible symlinks before checking for ld pattern - # this is necessary because some architectures (zSeries) - # use nonconforming ld symlink names, like ld64.so - libpath=`resolve_symlink $i` - case $libpath in - /lib/ld[.-]*) mode=${mode}px - ;; - /lib32/ld[.-]*) mode=${mode}px - ;; - /lib64/ld[.-]*) mode=${mode}px - ;; - *) mode=${mode}ix - ;; - esac - dynlibs="$dynlibs ${libpath}:${mode}" - done -} - runtestbg() { if [ -z "${__NO_TRAP_ERR}" ] @@ -337,31 +241,21 @@ emit_profile() trap "error_handler" ERR fi - local subprofile wflag + local wflag #global name outfile profile dynlibs profilenames - subprofile=0 wflag="" - case "$1" in - *^*) wflag="--nowarn" - subprofile=1 - ;; - esac - mkflags="${wflag} ${escapeflag}" + if [ "$nodefaults" -eq 1 ] + then + mkflags="${mkflags} -N" + fi + name=$1; perm=$2; shift 2 - if [ "$subprofile" -eq 1 -o "$nodefaults" -eq 1 ] - then - # skip dynamic libs for subprofiles - $bin/mkprofile.pl ${mkflags} "$name" ${outfile}:w "$@" >> $profile - - else - - $bin/mkprofile.pl ${mkflags} "$name" ${name}:${perm} $dynlibs ${outfile}:w "$@" >> $profile - fi + $bin/mkprofile.pl ${mkflags} "$name" ${outfile}:w "$@" >> $profile echo $name >> $profilenames } @@ -579,12 +473,6 @@ settest() outfile=$tmpdir/output.$1 - if [ -x $test ] - then - # build list of dynamic libraries required by this executable - resolve_libs $test - fi - # Remove any current profile if loaded if [ $profileloaded -eq 1 ] then