mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Regression testsuite: move the ldd analysis of binaries to the
mkprofile.pl helper and take the convoluted code out of the bash prologue.inc. It also detects if the binary is a script and performs ldd analysis on the interpreter. Signed-off-by: Steve Beattie <sbeattie@ubuntu.com> Acked-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
@@ -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 & regular env" pass ${helper_sh} FOO=BAR
|
||||||
runchecktest "ENVIRON (shell script): Ux & sensitive env" fail ${helper_sh} LD_LIBRARY_PATH=.
|
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 & regular env" pass ${helper_sh} FOO=BAR
|
||||||
runchecktest "ENVIRON (shell script): px & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=.
|
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 & regular env" pass ${helper_sh} FOO=BAR
|
||||||
runchecktest "ENVIRON (shell script): Px & sensitive env" fail ${helper_sh} LD_LIBRARY_PATH=.
|
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 & regular env" pass ${helper_sh} FOO=BAR
|
||||||
runchecktest "ENVIRON (shell script): ix & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=.
|
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 & regular env" pass ${helper_sh} FOO=BAR
|
||||||
runchecktest "ENVIRON (shell script): unconfined --> confined & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=.
|
runchecktest "ENVIRON (shell script): unconfined --> confined & sensitive env" pass ${helper_sh} LD_LIBRARY_PATH=.
|
||||||
|
|
||||||
|
@@ -9,9 +9,11 @@ my $__VERSION__=$0;
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
|
use Cwd 'realpath';
|
||||||
|
|
||||||
my $help = '';
|
my $help = '';
|
||||||
my $nowarn = '';
|
my $nowarn = '';
|
||||||
|
my $nodefault;
|
||||||
my $escape = '';
|
my $escape = '';
|
||||||
my %output_rules;
|
my %output_rules;
|
||||||
my $hat = "__no_hat";
|
my $hat = "__no_hat";
|
||||||
@@ -21,6 +23,7 @@ GetOptions(
|
|||||||
'escape|E' => \$escape,
|
'escape|E' => \$escape,
|
||||||
'nowarn' => \$nowarn,
|
'nowarn' => \$nowarn,
|
||||||
'help|h' => \$help,
|
'help|h' => \$help,
|
||||||
|
'nodefault|N' => \$nodefault,
|
||||||
);
|
);
|
||||||
|
|
||||||
sub usage {
|
sub usage {
|
||||||
@@ -28,12 +31,108 @@ sub usage {
|
|||||||
print STDERR "Usage $0 [--nowarn|--escape] execname [rules]\n";
|
print STDERR "Usage $0 [--nowarn|--escape] execname [rules]\n";
|
||||||
print STDERR " $0 --help\n";
|
print STDERR " $0 --help\n";
|
||||||
print STDERR " nowarn: don't warn if execname does not exist\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 " escape: escape stuff that would be treated as regexs\n";
|
||||||
print STDERR " help: print this message\n";
|
print STDERR " help: print this message\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
&usage && exit 0 if ($help || @ARGV < 1);
|
&usage && exit 0 if ($help || @ARGV < 1);
|
||||||
|
|
||||||
|
sub head ($) {
|
||||||
|
my $file = shift;
|
||||||
|
|
||||||
|
my $first = "";
|
||||||
|
if (open(FILE, $file)) {
|
||||||
|
$first = <FILE>;
|
||||||
|
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 (<KID_TO_READ>) {
|
||||||
|
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($) {
|
sub gen_netdomain($) {
|
||||||
my $rule = shift;
|
my $rule = shift;
|
||||||
# only split on single ':'s
|
# only split on single ':'s
|
||||||
@@ -103,8 +202,10 @@ sub gen_hat($) {
|
|||||||
my $bin = shift @ARGV;
|
my $bin = shift @ARGV;
|
||||||
!(-e $bin || $nowarn) && print STDERR "Warning: execname '$bin': no such file or directory\n";
|
!(-e $bin || $nowarn) && print STDERR "Warning: execname '$bin': no such file or directory\n";
|
||||||
|
|
||||||
# give every profile/hat access to change_hat
|
unless ($nodefault) {
|
||||||
gen_file("/proc/*/attr/current:w");
|
gen_default_rules();
|
||||||
|
gen_binary($bin);
|
||||||
|
}
|
||||||
|
|
||||||
for my $rule (@ARGV) {
|
for my $rule (@ARGV) {
|
||||||
#($fn, @rules) = split (/:/, $rule);
|
#($fn, @rules) = split (/:/, $rule);
|
||||||
|
@@ -85,102 +85,6 @@ genrunscript()
|
|||||||
fi
|
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()
|
runtestbg()
|
||||||
{
|
{
|
||||||
if [ -z "${__NO_TRAP_ERR}" ]
|
if [ -z "${__NO_TRAP_ERR}" ]
|
||||||
@@ -337,31 +241,21 @@ emit_profile()
|
|||||||
trap "error_handler" ERR
|
trap "error_handler" ERR
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local subprofile wflag
|
local wflag
|
||||||
#global name outfile profile dynlibs profilenames
|
#global name outfile profile dynlibs profilenames
|
||||||
|
|
||||||
subprofile=0
|
|
||||||
wflag=""
|
wflag=""
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
*^*) wflag="--nowarn"
|
|
||||||
subprofile=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
mkflags="${wflag} ${escapeflag}"
|
mkflags="${wflag} ${escapeflag}"
|
||||||
|
|
||||||
|
if [ "$nodefaults" -eq 1 ]
|
||||||
|
then
|
||||||
|
mkflags="${mkflags} -N"
|
||||||
|
fi
|
||||||
|
|
||||||
name=$1; perm=$2; shift 2
|
name=$1; perm=$2; shift 2
|
||||||
|
|
||||||
if [ "$subprofile" -eq 1 -o "$nodefaults" -eq 1 ]
|
$bin/mkprofile.pl ${mkflags} "$name" ${outfile}:w "$@" >> $profile
|
||||||
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
|
|
||||||
|
|
||||||
echo $name >> $profilenames
|
echo $name >> $profilenames
|
||||||
}
|
}
|
||||||
@@ -579,12 +473,6 @@ settest()
|
|||||||
|
|
||||||
outfile=$tmpdir/output.$1
|
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
|
# Remove any current profile if loaded
|
||||||
if [ $profileloaded -eq 1 ]
|
if [ $profileloaded -eq 1 ]
|
||||||
then
|
then
|
||||||
|
Reference in New Issue
Block a user