diff --git a/tests/Makefile b/tests/Makefile index 5ab0785..830abd2 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -13,6 +13,7 @@ endif # all of the tests TESTS := \ + containerid \ exec_execve \ exec_name \ file_create \ diff --git a/tests/containerid/Makefile b/tests/containerid/Makefile new file mode 100644 index 0000000..7ade09a --- /dev/null +++ b/tests/containerid/Makefile @@ -0,0 +1,8 @@ +TARGETS=$(patsubst %.c,%,$(wildcard *.c)) + +LDLIBS += -lpthread + +all: $(TARGETS) +clean: + rm -f $(TARGETS) + diff --git a/tests/containerid/test b/tests/containerid/test new file mode 100755 index 0000000..9907f9d --- /dev/null +++ b/tests/containerid/test @@ -0,0 +1,303 @@ +#!/usr/bin/perl + +use strict; +use File::Temp qw/ tempdir tempfile /; +use Test; +BEGIN { plan tests => 26 } + +### +# functions + +sub key_gen { + my @chars = ( "A" .. "Z", "a" .. "z" ); + my $key = "testsuite-" . time . "-"; + $key .= $chars[ rand @chars ] for 1 .. 8; + return $key; +} + +sub mark_gen { + my @chars = ( "A" .. "Z", "a" .. "z" ); + my $key = "testsuite-" . time . "-"; + $key .= $chars[ rand @chars ] for 1 .. 8; + return $key; +} + +### +# setup + +# reset audit rules +system("auditctl -D >& /dev/null"); + +# create stdout/stderr sinks +( my $fh_out, my $stdout ) = tempfile( + TEMPLATE => '/tmp/audit-testsuite-out-XXXX', + UNLINK => 1 +); +( my $fh_err, my $stderr ) = tempfile( + TEMPLATE => '/tmp/audit-testsuite-err-XXXX', + UNLINK => 1 +); +( my $fh_tmp, my $tmpout ) = tempfile( + TEMPLATE => '/tmp/audit-testsuite-tmp-XXXX', + UNLINK => 1 +); + +my $key = key_gen(); +my $result; + +my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = + localtime(time); +$year += 1900; +$mon += 1; +my $startdate = "$year-$mon-$mday"; +my $starttime = "$hour:$min:$sec"; + +my $contid_unset = 18446744073709551615; +my $contid1 = int( rand( 1 << 63 ) ); +my $contid2 = int( rand( 1 << 63 ) ); +my $contid3 = int( rand( 1 << 63 ) ); +my $contid4 = int( rand( 1 << 63 ) ); +my $contid5 = int( rand( 1 << 63 ) ); +my $contid6 = int( rand( 1 << 63 ) ); +my $contid7 = int( rand( 1 << 63 ) ); + +### +# tests +# Test self-set +# Start sleep to provide target tasks +seek( $fh_out, 0, 0 ); +system("sleep 2 >/dev/null 2>&1 & echo \$! >$stdout"); +my $task1_pid = <$fh_out>; +chomp($task1_pid); + +# Set the audit container identifier and save the pid responsible +seek( $fh_out, 0, 0 ); +$result = system( +"echo $contid1 > /proc/self/audit_containerid >/dev/null 2>&1 & echo \$! >$stdout" +); +ok( $result, 0 ); +my $self_pid = <$fh_out>; +chomp($self_pid); + +# Test unset +$result = system("echo $contid_unset > /proc/$task1_pid/audit_containerid"); +ok( $result != 0 ); # Did unset fail? + +# Test set +$result = system("echo $contid2 > /proc/$task1_pid/audit_containerid"); +ok( $result, 0 ); # Did set succeed? + +# Test set again +$result = system("echo $contid3 > /proc/$task1_pid/audit_containerid"); +ok( $result, 0 ); # Did set again succeed? + +# Test child with child fail +#FIXME, doesn't spawn child of child +seek( $fh_tmp, 0, 0 ); +system("bash -c \"sleep 2\" >/dev/null 2>&1 & echo \$! >$tmpout"); +my $task2_pid = <$fh_tmp>; +chomp($task2_pid); +$result = system("echo $contid4 > /proc/$task2_pid/audit_containerid"); +ok( $result != 0 ); # Did set with child fail? + +seek( $fh_out, 0, 0 ); +seek( $fh_err, 0, 0 ); +$result = system( + "ausearch -i -ts boot -m container_op --contid=$contid1 >$stdout 2>$stderr" +); +ok( $result, 0 ); # Was an event found? + +seek( $fh_tmp, 0, 0 ); +system("command >/dev/null 2>&1 & echo \$! >$tmpout"); +my $command_pid = <$fh_tmp>; +chomp($command_pid); + +## Add rule to ... +#$result = +#system("auditctl -a exit,always -F arch=b$ENV{MODE} ... -F key=$key >/dev/null 2>&1"); +#ok( $result, 0 ); # Was the rule added successfully? +#sleep 1; +#kill 'TERM', $ping_pid; +#system("auditctl -d exit,always -F arch=b$ENV{MODE} ... -F key=$key >/dev/null 2>&1"); + +# find the event +seek( $fh_out, 0, 0 ); +seek( $fh_err, 0, 0 ); +$result = system("ausearch -ts recent -i -m CONTAINER_OP >$stdout 2>$stderr"); +ok( $result, 0 ); # Was an event found? + +# test if we generate the lost reset record correctly +my $line; +my $contid1_found = 0; +my $contid_unset_found = 0; +my $contid2_found = 0; +my $contid3_found = 0; +my $contid4_found = 0; +while ( $line = <$fh_out> ) { + if ( $line =~ /^type=CONTAINER_OP / ) { + if ( $line =~ / opid=([0-9]+) contid=([0-9]+) / ) { + if ( $1 == $self_pid && $2 == $contid1 ) { + $contid1_found = 1; + } + elsif ( $1 == $task1_pid && $2 == $contid_unset ) { + $contid_unset_found = 1; + } + elsif ( $1 == $task1_pid && $2 == $contid2 ) { + $contid2_found = 1; + } + elsif ( $1 == $task1_pid && $2 == $contid3 ) { + $contid3_found = 1; + } + elsif ( $1 == $task2_pid && $2 == $contid4 ) { + $contid4_found = 1; + } + } + } +} +ok( $contid1_found, 1 ); # Was the contid1 message well-formed? +ok( $contid_unset_found, 1 ); # Was the contid_unset message well-formed? +ok( $contid2_found, 1 ); # Was the contid2 message well-formed? +ok( $contid3_found, 1 ); # Was the contid3 message well-formed? +ok( $contid4_found, 1 ); # Was the contid4 message well-formed? + +# Test filter on containerid +$result = system( +"auditctl -a exit,always -F arch=b$ENV{MODE} -F dir=/tmp -F perm=wa -F contid=$contid5 -F key=$key >/dev/null 2>&1" +); +ok( $result, 0 ); # Filter rule added successfully? +seek( $fh_out, 0, 0 ); +my $cmd = "sleep 1; open(my \$tmpfile, '>', \"/tmp/$key\"); close(\$tmpfile);"; +$result = system("perl -e \"$cmd\" >/dev/null 2>&1 & echo \$! >$stdout"); +ok( $result, 0 ); # Was the filter trigger successfully run? +my $task3_pid = <$fh_out>; +chomp($task3_pid); +$result = + system("echo $contid5 > /proc/$task3_pid/audit_containerid >/dev/null 2>&1"); +ok( $result, 0 ); # Was the audit container identifier set successful? +sleep 1; +unlink "/tmp/$key"; +system( +"auditctl -d exit,always -F arch=b$ENV{MODE} -F dir=/tmp -F perm=wa -F contid=$contid5 -F key=$key >/dev/null 2>&1" +); + +# find the event +seek( $fh_out, 0, 0 ); +seek( $fh_err, 0, 0 ); +$result = + system("ausearch -ts recent -i -m CONTAINER_ID -k $key >$stdout 2>$stderr"); +ok( $result, 0 ); # Was an event found? +my $contid5_found = 0; +while ( $line = <$fh_out> ) { + if ( $line =~ /^type=CONTAINER_ID / ) { + if ( $line =~ / contid=([0-9]+) / ) { + if ( $1 == $contid5 ) { + $contid5_found = 1; + } + } + } +} +ok( $contid5_found, 1 ); # Was the contid5 message well-formed? + +# Test multiple containers on one netns +# Create two child processes +seek( $fh_out, 0, 0 ); +system("sleep 2 >/dev/null 2>&1 & echo \$! >$stdout"); +my $task4_pid = <$fh_out>; +chomp($task4_pid); +$result = + system("echo $contid6 > /proc/$task4_pid/audit_containerid >/dev/null 2>&1"); +ok( $result, 0 ); # Was contid6 written to task4? +seek( $fh_out, 0, 0 ); +system("sleep 2 >/dev/null 2>&1 & echo \$! >$stdout"); +my $task5_pid = <$fh_out>; +chomp($task5_pid); +$result = + system("echo $contid7 > /proc/$task5_pid/audit_containerid >/dev/null 2>&1"); +ok( $result, 0 ); # Was contid7 written to task5? + +# Set up audit rules in netfilter and send a test packet +my $mark = int( rand(99999999) ); +$result = system( +"iptables -I INPUT -i lo -p icmp --icmp-type echo-request -j AUDIT --type accept >/dev/null 2>&1" +); +ok( $result, 0 ); # Was the iptables filter rule added successful +$result = system( +"iptables -I INPUT -t mangle -i lo -p icmp --icmp-type echo-request -j MARK --set-mark 0x$mark >/dev/null 2>&1" +); +ok( $result, 0 ); # Was the iptables mangle rule added successful +sleep 1; +$result = system("ping -q -c 1 127.0.0.1 >/dev/null 2>&1"); +ok( $result, 0 ); # Was ping successful? +sleep 1; +system( +"iptables -D INPUT -i lo -p icmp --icmp-type echo-request -j AUDIT --type accept >/dev/null 2>&1" +); +system( +"iptables -D INPUT -t mangle -i lo -p icmp --icmp-type echo-request -j MARK --set-mark 0x$mark >/dev/null 2>&1" +); + +# find the event +seek( $fh_out, 0, 0 ); +seek( $fh_err, 0, 0 ); +$result = system("ausearch -ts recent -i -m NETFILTER_PKT >$stdout 2>$stderr"); +ok( $result, 0 ); # Was an event found? +my $contid6_found = 0; +my $contid7_found = 0; +my $id = ""; +while ( $line = <$fh_out> ) { + + if ( $line =~ /^type=NETFILTER_PKT / ) { + if ( $line =~ / mark=0x$mark / ) { + ($id) = ( $line =~ / msg=audit\(.*:([0-9]*)\).* / ); + } + } +} +seek( $fh_out, 0, 0 ); +seek( $fh_err, 0, 0 ); +$result = system("ausearch -ts boot -i -a $id >$stdout 2>$stderr"); +ok( $result, 0 ); # Was an event found? +while ( $line = <$fh_out> ) { + if ( $line =~ /^type=CONTAINER_ID / ) { + if ( $line =~ / contid=([,0-9]+) / ) { + if ( $1 =~ /$contid6/ ) { + $contid6_found = 1; + } + if ( $1 =~ /$contid7/ ) { + $contid7_found = 1; + } + } + } +} +ok( $contid6_found, 1 ); # Was the contid6 message well-formed? +ok( $contid7_found, 1 ); # Was the contid7 message well-formed? + +if ( defined $ENV{ATS_DEBUG} && $ENV{ATS_DEBUG} == 1 ) { + if ( !$contid1_found ) { + print "self_pid=$self_pid contid1=$contid1\n"; + } + if ( !$contid_unset_found ) { + print "task1_pid=$task1_pid contid_unset=$contid_unset\n"; + } + if ( !$contid2_found ) { + print "task1_pid=$task1_pid contid2=$contid2\n"; + } + if ( !$contid3_found ) { + print "task1_pid=$task1_pid contid3=$contid3\n"; + } + if ( !$contid4_found ) { + print "task2_pid=$task2_pid contid4=$contid4\n"; + } + if ( !$contid5_found ) { + print "task3_pid=$task3_pid contid5=$contid5\n"; + } + if ( !$contid6_found ) { + print "mark=$mark id=$id contid6=$contid6\n"; + } + if ( !$contid5_found ) { + print "mark=$mark id=$id contid7=$contid7\n"; + } +} + +### +# cleanup +system("service auditd restart 2>/dev/null");