mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 06:16:03 +00:00
Merge from main branch
This commit is contained in:
14
README
14
README
@@ -146,6 +146,20 @@ For details on structure and adding tests, see libraries/libapparmor/README.
|
||||
$ cd libraries/libapparmor
|
||||
$ make check
|
||||
|
||||
Utils
|
||||
-----
|
||||
There are some simple tests available, including basic perl syntax
|
||||
checks for the perl modules and executables. There are also minimal
|
||||
checks on the python utilities and python-based tests in the test/
|
||||
subdirectory.
|
||||
$ cd utils
|
||||
$ make check
|
||||
|
||||
The aa-decode utility to be tested can be overridden by
|
||||
setting up environment variable APPARMOR_DECODE; e.g.:
|
||||
|
||||
$ APPARMOR_DECODE=/usr/bin/aa-decode make check
|
||||
|
||||
Profile checks
|
||||
--------------
|
||||
A basic consistency check to ensure that the parser and aa-logprof parse
|
||||
|
@@ -36,13 +36,13 @@ error_output: $(PARSER)
|
||||
@echo "Error Output: PASS"
|
||||
|
||||
parser_sanity: $(PARSER)
|
||||
$(Q)${PROVE} ${PROVE_ARG} ${TESTS}
|
||||
$(Q)LANG=C APPARMOR_PARSER="$(PARSER)" ${PROVE} ${PROVE_ARG} ${TESTS}
|
||||
|
||||
caching: $(PARSER)
|
||||
LANG=C ./caching.sh
|
||||
LANG=C APPARMOR_PARSER="$(PARSER)" ./caching.sh
|
||||
|
||||
minimize: $(PARSER)
|
||||
LANG=C ./minimize.sh
|
||||
LANG=C APPARMOR_PARSER="$(PARSER)" ./minimize.sh
|
||||
|
||||
$(PARSER):
|
||||
make -C $(PARSER_DIR) $(PARSER_BIN)
|
||||
|
@@ -9,6 +9,10 @@ There is a user configuration file 'uservars.conf'. If you wish to test
|
||||
against a different parser, or use a different set of profiles for the
|
||||
simple.pl test, you can change those settings in 'uservars.conf'.
|
||||
|
||||
You can also override which parser is used through make by specifying
|
||||
the PARSER veriable. For example, to run the tests on the system parser,
|
||||
run 'make PARSER=/sbin/apparmor_parser'.
|
||||
|
||||
Adding to the testsuite
|
||||
-----------------------
|
||||
|
||||
|
@@ -10,6 +10,8 @@ if [ ! -d /sys/kernel/security/apparmor ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
|
||||
|
||||
# fake base directory
|
||||
basedir=$(mktemp -d -t aa-cache-XXXXXX)
|
||||
trap "rm -rf $basedir" EXIT
|
||||
@@ -33,19 +35,19 @@ fi
|
||||
rm -f $basedir/test1 $basedir/test2
|
||||
|
||||
echo -n "Profiles are not cached by default: "
|
||||
../apparmor_parser $ARGS -q -r $basedir/$profile
|
||||
${APPARMOR_PARSER} $ARGS -q -r $basedir/$profile
|
||||
[ -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile exists)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Profiles are not cached when using --skip-cache: "
|
||||
../apparmor_parser $ARGS -q --write-cache --skip-cache -r $basedir/$profile
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache --skip-cache -r $basedir/$profile
|
||||
[ -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile exists)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
sleep $timeout
|
||||
|
||||
echo -n "Profiles are cached when requested: "
|
||||
../apparmor_parser $ARGS -q --write-cache -r $basedir/$profile
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache -r $basedir/$profile
|
||||
[ ! -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile does not exist)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
@@ -80,22 +82,22 @@ fi
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is loaded when it exists and features match: "
|
||||
../apparmor_parser $ARGS -v -r $basedir/$profile | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is not loaded when skipping is requested: "
|
||||
../apparmor_parser $ARGS -v --skip-read-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
../apparmor_parser $ARGS -v --skip-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v --skip-read-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v --skip-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when features do not match cache: "
|
||||
echo -n "monkey" > $basedir/cache/.features
|
||||
../apparmor_parser $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache writing is skipped when features do not match and not cleared: "
|
||||
rm $basedir/cache/$profile
|
||||
../apparmor_parser $ARGS -v --write-cache --skip-bad-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v --write-cache --skip-bad-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile exists)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
@@ -104,7 +106,7 @@ rm -f $basedir/cache/$profile || true
|
||||
echo -n "monkey" > $basedir/cache/.features
|
||||
echo -n "monkey" > $basedir/cache/$profile
|
||||
echo -n "monkey" > $basedir/cache/monkey
|
||||
../apparmor_parser $ARGS -v --write-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "Cache clear setup FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v --write-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "Cache clear setup FAIL"; exit 1; }
|
||||
echo -n "Cache clear updates features: "
|
||||
echo -n "monkey" | diff -q $basedir/cache/.features - | grep -q 'differ' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
@@ -122,7 +124,7 @@ echo -n "monkey" > $basedir/cache/.features
|
||||
echo -n "monkey" > $basedir/cache/$profile
|
||||
echo -n "monkey" > $basedir/cache/monkey
|
||||
echo -n "Cache purge remove profiles unconditionally: "
|
||||
../apparmor_parser $ARGS -v --purge-cache -r $basedir/$profile || { echo "Cache purge setup FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v --purge-cache -r $basedir/$profile || { echo "Cache purge setup FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/.features ] && { echo "FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/$profile ] && { echo "FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/monkey ] && { echo "FAIL"; exit 1; }
|
||||
@@ -131,25 +133,25 @@ echo "ok"
|
||||
echo -n "Profiles are cached when requested (again): "
|
||||
rm -f $basedir/cache/.features || true
|
||||
rm -f $basedir/cache/$profile || true
|
||||
../apparmor_parser $ARGS -q --write-cache -r $basedir/$profile
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache -r $basedir/$profile
|
||||
[ ! -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile does not exist)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when profile is newer: "
|
||||
sleep $timeout
|
||||
touch $basedir/$profile
|
||||
../apparmor_parser $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is used when cache is newer: "
|
||||
sleep $timeout
|
||||
touch $basedir/cache/$profile
|
||||
../apparmor_parser $ARGS -v -r $basedir/$profile | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when parser is newer: "
|
||||
mkdir $basedir/parser
|
||||
cp ../apparmor_parser $basedir/parser/
|
||||
cp ${APPARMOR_PARSER} $basedir/parser/
|
||||
$basedir/parser/apparmor_parser $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
|
@@ -1,5 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
|
||||
|
||||
# Format of -D dfa-states
|
||||
# dfa-states output is split into 2 parts:
|
||||
# the accept state infomation
|
||||
@@ -75,7 +78,7 @@
|
||||
# {a} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles basic perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -90,7 +93,7 @@ echo "ok"
|
||||
# {9} (0x 12804a/0/2800a/0)
|
||||
# {c} (0x 40030/0/0/0)
|
||||
echo -n "Minimize profiles audit perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -109,7 +112,7 @@ echo "ok"
|
||||
# {c} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles deny perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -127,7 +130,7 @@ echo "ok"
|
||||
# {c} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles audit deny perms "
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 5 ] ; then
|
||||
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 5 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -159,7 +162,7 @@ echo "ok"
|
||||
#
|
||||
|
||||
echo -n "Minimize profiles xtrans "
|
||||
if [ `echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
|
||||
if [ `echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -167,7 +170,7 @@ echo "ok"
|
||||
|
||||
# same test as above + audit
|
||||
echo -n "Minimize profiles audit xtrans "
|
||||
if [ `echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
|
||||
if [ `echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -180,7 +183,7 @@ echo "ok"
|
||||
# {3} (0x 0/fe17f85/0/14005)
|
||||
|
||||
echo -n "Minimize profiles deny xtrans "
|
||||
if [ `echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 1 ] ; then
|
||||
if [ `echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 1 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -192,7 +195,7 @@ echo "ok"
|
||||
# {3} (0x 0/fe17f85/0/0)
|
||||
|
||||
echo -n "Minimize profiles audit deny xtrans "
|
||||
if [ `echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ../apparmor_parser -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 0 ] ; then
|
||||
if [ `echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 0 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
|
@@ -8,7 +8,7 @@ use Getopt::Long;
|
||||
use Test::More;
|
||||
|
||||
my %config;
|
||||
$config{'parser'} = "/sbin/subdomain_parser";
|
||||
$config{'parser'} = "/sbin/apparmor_parser";
|
||||
$config{'profiledir'} = "./simple_tests/";
|
||||
$config{'timeout'} = 120; # in seconds
|
||||
|
||||
@@ -30,6 +30,12 @@ sub usage {
|
||||
&usage if ($help);
|
||||
read_config();
|
||||
|
||||
# let environment variable override config file, for use in automated
|
||||
# test suites
|
||||
if ($ENV{APPARMOR_PARSER}) {
|
||||
$config{'parser'} = $ENV{APPARMOR_PARSER};
|
||||
}
|
||||
|
||||
# Override config file profile location when passed on command line
|
||||
if (@ARGV >= 1) {
|
||||
$config{'profiledir'} = shift;
|
||||
@@ -68,6 +74,16 @@ sub test_profile {
|
||||
my $result = 0;
|
||||
my $child;
|
||||
|
||||
$child = open(PARSER, "|-");
|
||||
if ($child == 0) {
|
||||
# child
|
||||
open(STDOUT, ">/dev/null") or die "Failed to redirect STDOUT";
|
||||
open(STDERR, ">/dev/null") or die "Failed to redirect STDERR";
|
||||
exec("$config{'parser'}", "-S", "-I", "$config{'includedir'}") or die "Bail out! couldn't open parser";
|
||||
# noreturn
|
||||
}
|
||||
|
||||
# parent
|
||||
eval {
|
||||
local $SIG{ALRM} = sub {
|
||||
$result = 1;
|
||||
@@ -77,19 +93,9 @@ sub test_profile {
|
||||
|
||||
alarm $config{'timeout'};
|
||||
|
||||
$child = open(PARSER, "|-");
|
||||
if ($child == 0) {
|
||||
# child
|
||||
open(STDOUT, ">/dev/null") or die "Failed to redirect STDOUT";
|
||||
open(STDERR, ">/dev/null") or die "Failed to redirect STDERR";
|
||||
exec("$config{'parser'}", "-S", "-I", "$config{'includedir'}") or die "Bail out! couldn't open parser";
|
||||
# noreturn
|
||||
}
|
||||
|
||||
# parent
|
||||
open(PROFILE, $profile) or die "Bail out! couldn't open profile $profile";
|
||||
while (<PROFILE>) {
|
||||
if (/^#=DESCRIPTION\s*(.*)/) {
|
||||
if (/^#=DESCRIPTION\s*(.*)/i) {
|
||||
$description = $1;
|
||||
} elsif (/^#=EXRESULT\s*(\w+)/) {
|
||||
if ($1 eq "PASS") {
|
||||
|
35
profiles/apparmor.d/usr.sbin.winbindd
Normal file
35
profiles/apparmor.d/usr.sbin.winbindd
Normal file
@@ -0,0 +1,35 @@
|
||||
# Last Modified: Mon Mar 26 20:28:18 2012
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/sbin/winbindd {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
/etc/samba/dhcp.conf r,
|
||||
/etc/samba/passdb.tdb rwk,
|
||||
/etc/samba/secrets.tdb rwk,
|
||||
@{PROC}/sys/kernel/core_pattern r,
|
||||
/tmp/.winbindd/ w,
|
||||
/usr/lib*/samba/idmap/*.so mr,
|
||||
/usr/lib*/samba/nss_info/*.so mr,
|
||||
/usr/sbin/winbindd mr,
|
||||
/var/lib/samba/account_policy.tdb rwk,
|
||||
/var/lib/samba/gencache.tdb rwk,
|
||||
/var/lib/samba/gencache_notrans.tdb rwk,
|
||||
/var/lib/samba/group_mapping.tdb rwk,
|
||||
/var/lib/samba/messages.tdb rwk,
|
||||
/var/lib/samba/netsamlogon_cache.tdb rwk,
|
||||
/var/lib/samba/serverid.tdb rwk,
|
||||
/var/lib/samba/winbindd_cache.tdb rwk,
|
||||
/var/lib/samba/winbindd_privileged/pipe w,
|
||||
/var/log/samba/cores/ rw,
|
||||
/var/log/samba/cores/winbindd/ rw,
|
||||
/var/log/samba/cores/winbindd/** rw,
|
||||
/var/log/samba/log.wb-* w,
|
||||
/var/log/samba/log.winbindd rw,
|
||||
/{var/,}run/samba/winbindd.pid rwk,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.sbin.winbindd>
|
||||
|
||||
}
|
203
utils/test/test-aa-decode.py
Executable file
203
utils/test/test-aa-decode.py
Executable file
@@ -0,0 +1,203 @@
|
||||
#! /usr/bin/env python
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2011-2012 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
# The locationg of the aa-decode utility can be overridden by setting
|
||||
# the APPARMOR_DECODE environment variable; this is useful for running
|
||||
# these tests in an installed environment
|
||||
aadecode_bin = "./aa-decode"
|
||||
|
||||
# http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/2009-07-02-python-sigpipe.html
|
||||
# This is needed so that the subprocesses that produce endless output
|
||||
# actually quit when the reader goes away.
|
||||
def subprocess_setup():
|
||||
# Python installs a SIGPIPE handler by default. This is usually not what
|
||||
# non-Python subprocesses expect.
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||||
|
||||
def cmd(command, input = None, stderr = subprocess.STDOUT, stdout = subprocess.PIPE, stdin = None, timeout = None):
|
||||
'''Try to execute given command (array) and return its stdout, or return
|
||||
a textual error if it failed.'''
|
||||
|
||||
try:
|
||||
sp = subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, preexec_fn=subprocess_setup)
|
||||
except OSError as e:
|
||||
return [127, str(e)]
|
||||
|
||||
out, outerr = sp.communicate(input)
|
||||
# Handle redirection of stdout
|
||||
if out == None:
|
||||
out = b''
|
||||
# Handle redirection of stderr
|
||||
if outerr == None:
|
||||
outerr = b''
|
||||
return [sp.returncode, out.decode('utf-8') + outerr.decode('utf-8')]
|
||||
|
||||
|
||||
def mkstemp_fill(contents, suffix='', prefix='tst-aadecode-', dir=None):
|
||||
'''As tempfile.mkstemp does, return a (file, name) pair, but with prefilled contents.'''
|
||||
|
||||
handle, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir)
|
||||
os.close(handle)
|
||||
handle = open(name, "w+")
|
||||
handle.write(contents)
|
||||
handle.flush()
|
||||
handle.seek(0)
|
||||
|
||||
return handle, name
|
||||
|
||||
class AADecodeTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tmpfile = None
|
||||
|
||||
def tearDown(self):
|
||||
if self.tmpfile and os.path.exists(self.tmpfile):
|
||||
os.remove(self.tmpfile)
|
||||
|
||||
def test_help(self):
|
||||
'''Test --help argument'''
|
||||
|
||||
expected = 0
|
||||
rc, report = cmd([aadecode_bin, "--help"])
|
||||
result = 'Got exit code %d, expected %d\n' % (rc, expected)
|
||||
self.assertEqual(expected, rc, result + report)
|
||||
|
||||
def _run_file_test(self, content, expected_list):
|
||||
'''test case helper function; takes log content and a list of
|
||||
expected strings as arguments'''
|
||||
|
||||
expected = 0
|
||||
|
||||
(f, self.tmpfile) = mkstemp_fill(content)
|
||||
|
||||
rc, report = cmd([aadecode_bin], stdin=f)
|
||||
result = 'Got exit code %d, expected %d\n' % (rc, expected)
|
||||
self.assertEqual(expected, rc, result + report)
|
||||
for expected_string in expected_list:
|
||||
result = 'could not find expected %s in output:\n' % (expected_string)
|
||||
self.assertIn(expected_string, report, result + report)
|
||||
f.close()
|
||||
|
||||
def test_simple_decode(self):
|
||||
'''Test simple decode on command line'''
|
||||
|
||||
expected = 0
|
||||
expected_output = 'Decoded: /tmp/foo bar'
|
||||
test_code = '2F746D702F666F6F20626172'
|
||||
|
||||
rc, report = cmd([aadecode_bin, test_code])
|
||||
result = 'Got exit code %d, expected %d\n' % (rc, expected)
|
||||
self.assertEqual(expected, rc, result + report)
|
||||
result = 'Got output "%s", expected "%s"\n' % (report, expected_output)
|
||||
self.assertIn(expected_output, report, result + report)
|
||||
|
||||
def test_simple_filter(self):
|
||||
'''test simple decoding of the name argument'''
|
||||
|
||||
expected_string = 'name="/tmp/foo bar"'
|
||||
content = \
|
||||
'''type=AVC msg=audit(1348982151.183:2934): apparmor="DENIED" operation="open" parent=30751 profile="/usr/lib/firefox/firefox{,*[^s] [^h]}" name=2F746D702F666F6F20626172 pid=30833 comm="plugin-containe" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
|
||||
'''
|
||||
|
||||
self._run_file_test(content, [expected_string])
|
||||
|
||||
def test_simple_multiline(self):
|
||||
'''test simple multiline decoding of the name argument'''
|
||||
|
||||
expected_strings = ['ses=4294967295 new ses=2762',
|
||||
'name="/tmp/foo bar"',
|
||||
'name="/home/steve/tmp/my test file"']
|
||||
content = \
|
||||
''' type=LOGIN msg=audit(1348980001.155:2925): login pid=17875 uid=0 old auid=4294967295 new auid=0 old ses=4294967295 new ses=2762
|
||||
type=AVC msg=audit(1348982151.183:2934): apparmor="DENIED" operation="open" parent=30751 profile="/usr/lib/firefox/firefox{,*[^s] [^h]}" name=2F746D702F666F6F20626172 pid=30833 comm="plugin-containe" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
|
||||
type=AVC msg=audit(1348982148.195:2933): apparmor="DENIED" operation="file_lock" parent=5490 profile="/usr/lib/firefox/firefox{,*[^s][^h]}" name=2F686F6D652F73746576652F746D702F6D7920746573742066696C65 pid=30737 comm="firefox" requested_mask="k" denied_mask="k" fsuid=1000 ouid=1000
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
def test_simple_profile(self):
|
||||
'''test simple decoding of the profile argument'''
|
||||
|
||||
'''Example take from LP: #897957'''
|
||||
expected_strings = ['name="/lib/x86_64-linux-gnu/libdl-2.13.so"',
|
||||
'profile="/test space"']
|
||||
content = \
|
||||
'''[289763.843292] type=1400 audit(1322614912.304:857): apparmor="ALLOWED" operation="getattr" parent=16001 profile=2F74657374207370616365 name="/lib/x86_64-linux-gnu/libdl-2.13.so" pid=17011 comm="bash" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
def test_simple_profile2(self):
|
||||
'''test simple decoding of name and profile argument'''
|
||||
|
||||
'''Example take from LP: #897957'''
|
||||
expected_strings = ['name="/home/steve/tmp/my test file"',
|
||||
'profile="/home/steve/tmp/my prog.sh"']
|
||||
content = \
|
||||
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile=2F686F6D652F73746576652F746D702F6D792070726F672E7368 name=2F686F6D652F73746576652F746D702F6D7920746573742066696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
def test_simple_embedded_carat(self):
|
||||
'''test simple decoding of embedded ^ in files'''
|
||||
|
||||
expected_strings = ['name="/home/steve/tmp/my test ^file"']
|
||||
content = \
|
||||
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374205E66696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
def test_simple_embedded_backslash_carat(self):
|
||||
'''test simple decoding of embedded \^ in files'''
|
||||
|
||||
expected_strings = ['name="/home/steve/tmp/my test \^file"']
|
||||
content = \
|
||||
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374205C5E66696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
def test_simple_embedded_singlequote(self):
|
||||
'''test simple decoding of embedded \' in files'''
|
||||
|
||||
expected_strings = ['name="/home/steve/tmp/my test \'file"']
|
||||
content = \
|
||||
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374202766696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
def test_simple_encoded_nonpath_profiles(self):
|
||||
'''test simple decoding of nonpath profiles'''
|
||||
|
||||
expected_strings = ['name="/lib/x86_64-linux-gnu/libdl-2.13.so"',
|
||||
'profile="test space"']
|
||||
content = \
|
||||
'''[289763.843292] type=1400 audit(1322614912.304:857): apparmor="ALLOWED" operation="getattr" parent=16001 profile=74657374207370616365 name="/lib/x86_64-linux-gnu/libdl-2.13.so" pid=17011 comm="bash" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
|
||||
'''
|
||||
|
||||
self._run_file_test(content, expected_strings)
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
if 'APPARMOR_DECODE' in os.environ:
|
||||
aadecode_bin = os.environ['APPARMOR_DECODE']
|
||||
unittest.main()
|
Reference in New Issue
Block a user