Skip to content

Commit

Permalink
tests: add test for contid
Browse files Browse the repository at this point in the history
See: linux-audit#64

Signed-off-by: Richard Guy Briggs <[email protected]>
  • Loading branch information
rgbriggs committed Sep 29, 2020
1 parent 1e94f53 commit c2c1346
Show file tree
Hide file tree
Showing 3 changed files with 390 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ endif

# all of the tests
TESTS := \
containerid \
exec_execve \
exec_name \
file_create \
Expand Down
8 changes: 8 additions & 0 deletions tests/containerid/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
TARGETS=$(patsubst %.c,%,$(wildcard *.c))

LDLIBS += -lpthread

all: $(TARGETS)
clean:
rm -f $(TARGETS)

381 changes: 381 additions & 0 deletions tests/containerid/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,381 @@
#!/usr/bin/perl

use strict;
use File::Temp qw/ tempdir tempfile /;
use Test;
use IO::Handle;
BEGIN { plan tests => 34 }

###
# 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 $tmpdir = tempdir(
TEMPLATE => '/tmp/audit-testsuite-dir-XXXX',
CLEANUP => 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 $contidself = int( rand( 1 << 63 ) );
my $contid1 = int( rand( 1 << 63 ) );
my $contid_unset = 18446744073709551615;
my $contid1a = 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 ) );

###
# tests
# Test self-set
seek( $fh_out, 0, 0 );

# Set the audit container identifier and save the pid responsible
my $resultself;
my $self_pid = fork();
if ( not $self_pid ) {
open( my $contidfd, '>', "/proc/self/audit_containerid" );
$contidfd->autoflush(1);
$resultself = print $contidfd $contidself;
if ( not $resultself ) {
$resultself = $!;
}
close($contidfd);
exit $resultself;
}
my $wait_pid = wait();
$resultself = $? >> 8;
ok( $self_pid > 0 ); # Did taskself start ok?
ok( $resultself != 1 ); # Did self-set fail?

# Start sleep to provide target task
my $task1_pid = fork();
if ( not $task1_pid ) {
sleep 2;
exit;
}
sleep .01;
ok( $task1_pid > 0 ); # Did task1 start ok?

# Test set
open( my $contidfd, '>', "/proc/$task1_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd "$contid1\n";
close($contidfd);
ok($result); # Did set succeed?

# Test set same
open( $contidfd, '>', "/proc/$task1_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd "$contid1\n";
close($contidfd);
ok( not $result ); # Did set same fail?

# Test unset
open( $contidfd, '>', "/proc/$task1_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd $contid_unset;
close($contidfd);
ok( not $result ); # Did unset fail?

# Test set again by same orch
open( $contidfd, '>', "/proc/$task1_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd $contid1a;
close($contidfd);
ok( not $result ); # Did set again fail?

# Test task injection to existing container
# Start sleep to provide injection target task
my $task1a_pid = fork();
if ( not $task1a_pid ) {
sleep 2;
exit;
}
sleep .01;
ok( $task1a_pid > 0 ); # Did task1a start ok?

# Test task injection
open( $contidfd, '>', "/proc/$task1a_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd "$contid1\n";
close($contidfd);
ok($result); # Did injection succeed?

# Test child with child fail
my $task2_pid = fork();
if ( not $task2_pid ) {
my $task2child_pid = fork();
if ( not $task2child_pid ) {
sleep 2;
exit;
}
wait();
exit;
}
sleep 1;
open( $contidfd, '>', "/proc/$task2_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd $contid2;
close($contidfd);
ok( not $result ); # Did set child with child fail?
ok( $task2_pid > 0 ); # Did task2 start ok?

# find the events
seek( $fh_out, 0, 0 );
seek( $fh_err, 0, 0 );
$result = system(
"LC_TIME=\"en_DK.utf8\" ausearch -ts $startdate $starttime -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 $contidself_found = 0;
my $contid1_found = 0;
my $contid_unset_found = 0;
my $contid1a_found = 0;
my $contid1i_found = 0;
my $contid2_found = 0;

while ( $line = <$fh_out> ) {

if ( $line =~ /^type=CONTAINER_OP / ) {
if ( $line =~ / opid=([0-9]+) contid=([0-9]+) / ) {
if ( $1 == $self_pid && $2 == $contidself ) {
$contidself_found = 1;
}
elsif ( $1 == $task1_pid && $2 == $contid1 ) {
$contid1_found = 1;
}
elsif ( $1 == $task1_pid && $2 == $contid_unset ) {
$contid_unset_found = 1;
}
elsif ( $1 == $task1_pid && $2 == $contid1a ) {
$contid1a_found = 1;
}
elsif ( $1 == $task1a_pid && $2 == $contid1 ) {
$contid1i_found = 1;
}
elsif ( $1 == $task2_pid && $2 == $contid2 ) {
$contid2_found = 1;
}
}
}
}
ok( $contidself_found, 1 ); # Was the contidself message well-formed?
ok( $contid1_found, 1 ); # Was the contid1 message well-formed?
ok( $contid_unset_found, 1 ); # Was the contid_unset message well-formed?
ok( $contid1a_found, 1 ); # Was the contid1a message well-formed?
ok( $contid1i_found, 1 ); # Was the contid1i message well-formed?
ok( $contid2_found, 1 ); # Was the contid2 message well-formed?

# Test filter on containerid
$result = system(
"auditctl -a exit,always -F arch=b$ENV{MODE} -F dir=$tmpdir -F perm=wa -F contid=$contid3 -F key=$key >/dev/null 2>&1"
);
ok( $result, 0 ); # Filter rule added successfully?
my $task3_pid = fork();
if ( not $task3_pid ) {
sleep 1;
open( $contidfd, '>', "$tmpdir/$key" );
$contidfd->autoflush(1);
print $contidfd $contid3;
close($contidfd);
exit;
}
sleep .01;
open( $contidfd, '>', "/proc/$task3_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd $contid3;
close($contidfd);
ok($result); # Was the filter trigger successfully run?
ok( $task3_pid > 0 ); # Did task3 start ok?
sleep 1;
system(
"auditctl -d exit,always -F arch=b$ENV{MODE} -F dir=$tmpdir -F perm=wa -F contid=$contid3 -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 $contid3_found = 0;
while ( $line = <$fh_out> ) {
if ( $line =~ /^type=CONTAINER_ID / ) {
if ( $line =~ / contid=([0-9]+)/ ) {
if ( $1 == $contid3 ) {
$contid3_found = 1;
}
}
}
}
ok( $contid3_found, 1 ); # Was the contid3 message well-formed?

# Test multiple containers on one netns
# Create two child processes
my $task4_pid = fork();
if ( not $task4_pid ) {
sleep 2;
exit;
}
ok( $task4_pid > 0 ); # Did task4 start ok?
sleep .01;
open( $contidfd, '>', "/proc/$task4_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd $contid4;
close($contidfd);
ok($result); # Was contid4 written to task4?
my $task5_pid = fork();

if ( not $task5_pid ) {
sleep 2;
exit;
}
ok( $task5_pid > 0 ); # Did task5 start ok?
sleep .01;
open( $contidfd, '>', "/proc/$task5_pid/audit_containerid" );
$contidfd->autoflush(1);
$result = print $contidfd $contid5;
close($contidfd);
ok($result); # Was contid5 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(
"LC_TIME=\"en_DK.utf8\" ausearch -ts $startdate $starttime -i -m NETFILTER_PKT >$stdout 2>$stderr"
);
ok( $result, 0 ); # Was an event found?
my $contid4_found = 0;
my $contid5_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 -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]+)/ ) {
my $contids = $1;
if ( $contids =~ /$contid4/ ) {
$contid4_found = 1;
}
if ( $contids =~ /$contid5/ ) {
$contid5_found = 1;
}
}
}
}
ok( $contid4_found, 1 ); # Was the contid4 message well-formed?
ok( $contid5_found, 1 ); # Was the contid5 message well-formed?

if ( defined $ENV{ATS_DEBUG} && $ENV{ATS_DEBUG} == 1 ) {
print "\ndebug: start\n";
if ( !$contidself_found || !$resultself ) {
print
"self_pid=$self_pid contidself=$contidself resultself=$resultself\n";
}
if ( !$contid1_found ) {
print "task1_pid=$task1_pid contid1=$contid1\n";
}
if ( !$contid_unset_found ) {
print "task1_pid=$task1_pid contid_unset=$contid_unset\n";
}
if ( !$contid1a_found ) {
print "task1_pid=$task1_pid contid1a=$contid1a\n";
}
if ( !$contid1i_found ) {
print "task1a_pid=$task1a_pid contid1i=$contid1\n";
}
if ( !$contid2_found ) {
print "task2_pid=$task2_pid contid2=$contid2\n";
}
if ( !$contid3_found ) {
print "task3_pid=$task3_pid contid3=$contid3 dir=$tmpdir key=$key\n";
}
if ( !$contid4_found ) {
print "mark=$mark id=$id contid4=$contid4\n";
}
if ( !$contid5_found ) {
print "mark=$mark id=$id contid5=$contid5\n";
}
print "debug: end\n\n\n";
}

###
# cleanup
system("service auditd restart 2>/dev/null");

0 comments on commit c2c1346

Please sign in to comment.