diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile index 497652bfc..c0aad62af 100644 --- a/tests/regression/apparmor/Makefile +++ b/tests/regression/apparmor/Makefile @@ -135,6 +135,21 @@ Install libdbus-1-dev or equivalent package to build and run these tests${nl}\ ************************************************************************${nl}) endif +ifdef USE_SYSTEM + ifneq (,$(shell pkg-config --atleast-version 2.10 libapparmor && echo TRUE)) + SRC+=aa_policy_cache.c + AA_POLICY_CACHE_TEST=aa_policy_cache + else + $(warning ${nl}\ + ************************************************************************${nl}\ + Skipping aa_policy_cache tests: requires libapparmor 2.10 or newer ...${nl}\ + ************************************************************************${nl}) + endif +else + SRC+=aa_policy_cache.c + AA_POLICY_CACHE_TEST=aa_policy_cache +endif + EXEC=$(SRC:%.c=%) TESTS=access \ @@ -195,6 +210,8 @@ ifneq (,$(shell pkg-config --exists dbus-1 && echo TRUE)) TESTS+=dbus_eavesdrop dbus_message dbus_service dbus_unrequested_reply endif +TESTS+=$(AA_POLICY_CACHE_TEST) + # Tests that can crash the kernel should be placed here RISKY_TESTS= diff --git a/tests/regression/apparmor/aa_policy_cache.c b/tests/regression/apparmor/aa_policy_cache.c new file mode 100644 index 000000000..b08fd1f8d --- /dev/null +++ b/tests/regression/apparmor/aa_policy_cache.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2015 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Canonical Ltd. + */ + +#include +#include +#include +#include +#include + +#include + +#define OPT_CREATE "create" +#define OPT_IS_VALID "is-valid" +#define OPT_NEW "new" +#define OPT_NEW_CREATE "new-create" +#define OPT_REMOVE "remove" +#define OPT_REMOVE_POLICY "remove-policy" +#define OPT_REPLACE_ALL "replace-all" + +static void usage(const char *prog) +{ + fprintf(stderr, + "FAIL - usage: %s %s \n" + " %s %s \n" + " %s %s \n" + " %s %s \n" + " %s %s \n" + " %s %s \n" + " %s %s \n", + prog, OPT_CREATE, prog, OPT_IS_VALID, prog, OPT_NEW, + prog, OPT_NEW_CREATE, prog, OPT_REMOVE, prog, OPT_REMOVE_POLICY, + prog, OPT_REPLACE_ALL); +} + +static int test_create(const char *path) +{ + aa_features *features = NULL; + aa_policy_cache *policy_cache = NULL; + int rc = 1; + + if (aa_features_new_from_kernel(&features)) { + perror("FAIL - aa_features_new_from_kernel"); + goto out; + } + + if (aa_policy_cache_new(&policy_cache, features, path, false)) { + perror("FAIL - aa_policy_cache_new"); + goto out; + } + + if (aa_policy_cache_create(policy_cache)) { + perror("FAIL - aa_policy_cache_create"); + goto out; + } + + rc = 0; +out: + aa_features_unref(features); + aa_policy_cache_unref(policy_cache); + return rc; +} + +static int test_is_valid(const char *path) +{ + aa_features *features = NULL; + aa_policy_cache *policy_cache = NULL; + int rc = 1; + + if (aa_features_new_from_kernel(&features)) { + perror("FAIL - aa_features_new_from_kernel"); + goto out; + } + + if (aa_policy_cache_new(&policy_cache, features, path, false)) { + perror("FAIL - aa_policy_cache_new"); + goto out; + } + + if (!aa_policy_cache_is_valid(policy_cache)) { + errno = EINVAL; + perror("FAIL - aa_policy_cache_is_valid"); + goto out; + } + + rc = 0; +out: + aa_features_unref(features); + aa_policy_cache_unref(policy_cache); + return rc; +} + +static int test_new(const char *path, bool create) +{ + aa_features *features = NULL; + aa_policy_cache *policy_cache = NULL; + int rc = 1; + + if (aa_features_new_from_kernel(&features)) { + perror("FAIL - aa_features_new_from_kernel"); + goto out; + } + + if (aa_policy_cache_new(&policy_cache, features, path, create)) { + perror("FAIL - aa_policy_cache_new"); + goto out; + } + + rc = 0; +out: + aa_features_unref(features); + aa_policy_cache_unref(policy_cache); + return rc; +} + +static int test_remove(const char *path) +{ + int rc = 1; + + if (aa_policy_cache_remove(path)) { + perror("FAIL - aa_policy_cache_remove"); + goto out; + } + + rc = 0; +out: + return rc; +} + +static int test_remove_policy(const char *name) +{ + aa_features *features = NULL; + aa_kernel_interface *kernel_interface = NULL; + int rc = 1; + + if (aa_features_new_from_kernel(&features)) { + perror("FAIL - aa_features_new_from_kernel"); + goto out; + } + + if (aa_kernel_interface_new(&kernel_interface, features, NULL)) { + perror("FAIL - aa_kernel_interface_new"); + goto out; + } + + if (aa_kernel_interface_remove_policy(kernel_interface, name)) { + perror("FAIL - aa_kernel_interface_remove_policy"); + goto out; + } + + rc = 0; +out: + aa_kernel_interface_unref(kernel_interface); + aa_features_unref(features); + return rc; +} + +static int test_replace_all(const char *path) +{ + aa_features *features = NULL; + aa_policy_cache *policy_cache = NULL; + int rc = 1; + + if (aa_features_new_from_kernel(&features)) { + perror("FAIL - aa_features_new_from_kernel"); + goto out; + } + + if (aa_policy_cache_new(&policy_cache, features, path, false)) { + perror("FAIL - aa_policy_cache_new"); + goto out; + } + + if (aa_policy_cache_replace_all(policy_cache, NULL)) { + perror("FAIL - aa_policy_cache_replace_all"); + goto out; + } + + rc = 0; +out: + aa_features_unref(features); + aa_policy_cache_unref(policy_cache); + return rc; +} + +int main(int argc, char **argv) +{ + int rc = 1; + + if (argc != 3) { + usage(argv[0]); + exit(1); + } + + if (strcmp(argv[1], OPT_CREATE) == 0) { + rc = test_create(argv[2]); + } else if (strcmp(argv[1], OPT_IS_VALID) == 0) { + rc = test_is_valid(argv[2]); + } else if (strcmp(argv[1], OPT_NEW) == 0) { + rc = test_new(argv[2], false); + } else if (strcmp(argv[1], OPT_NEW_CREATE) == 0) { + rc = test_new(argv[2], true); + } else if (strcmp(argv[1], OPT_REMOVE) == 0) { + rc = test_remove(argv[2]); + } else if (strcmp(argv[1], OPT_REMOVE_POLICY) == 0) { + rc = test_remove_policy(argv[2]); + } else if (strcmp(argv[1], OPT_REPLACE_ALL) == 0) { + rc = test_replace_all(argv[2]); + } else { + usage(argv[0]); + } + + if (!rc) + printf("PASS\n"); + + exit(rc); +} diff --git a/tests/regression/apparmor/aa_policy_cache.sh b/tests/regression/apparmor/aa_policy_cache.sh new file mode 100755 index 000000000..fb9a830e1 --- /dev/null +++ b/tests/regression/apparmor/aa_policy_cache.sh @@ -0,0 +1,149 @@ +#! /bin/bash +# Copyright (C) 2015 Canonical, Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, version 2 of the +# License. + +#=NAME aa_policy_cache +#=DESCRIPTION +# This test verifies that the aa_policy_cache API works as expected. +#=END + +pwd=`dirname $0` +pwd=`cd $pwd ; /bin/pwd` + +bin=$pwd + +. $bin/prologue.inc + +cachedir=$tmpdir/cache +policies=$(echo aa_policy_cache_test_{0001..1024}) + +create_cachedir() +{ + mkdir -p "$cachedir" +} + +remove_cachedir() +{ + if [ -n "$cachedir" ] + then + rm -rf "$cachedir" + fi +} + +create_empty_cache() +{ + $test new-create "$cachedir" > /dev/null +} + +create_cache_files() +{ + local cachefile + + create_cachedir + for policy in $policies + do + cachefile="${cachedir}/${policy}" + + echo "profile $policy { /f r, }" | ${subdomain} -qS > "$cachefile" + done +} + +install_bad_features_file() +{ + echo "file {\n}\n" > "${cachedir}/.features" +} + +remove_features_file() +{ + if [ -n "$cachedir" ] + then + rm -f "${cachedir}/.features" + fi +} + +verify_policies_are_not_loaded() +{ + for policy in $policies + do + if grep -q "^policy " /sys/kernel/security/apparmor/profiles + then + fatalerror "Policy \"${policy}\" must not be loaded" + return + fi + done +} + +runchecktest_policies_are_loaded() +{ + for policy in $policies + do + if ! grep -q "^$policy (enforce)" /sys/kernel/security/apparmor/profiles + then + echo "Error: Policy \"${policy}\" was not loaded" + testfailed + return + fi + done +} + +runchecktest_remove_policies() +{ + for policy in $policies + do + runchecktest "AA_POLICY_CACHE remove-policy ($policy)" pass remove-policy "$policy" + done +} + +# IMPORTANT: These tests build on themselves so the first failing test can +# cause many failures + +runchecktest "AA_POLICY_CACHE new (no cachedir)" fail new "$cachedir" +create_cachedir +runchecktest "AA_POLICY_CACHE new (no .features)" fail new "$cachedir" +remove_cachedir +runchecktest "AA_POLICY_CACHE new-create (no cachedir)" pass new-create "$cachedir" +runchecktest "AA_POLICY_CACHE new-create (existing cache)" pass new-create "$cachedir" +runchecktest "AA_POLICY_CACHE new (existing cache)" pass new "$cachedir" + +runchecktest "AA_POLICY_CACHE is-valid (good .features)" pass is-valid "$cachedir" +install_bad_features_file +runchecktest "AA_POLICY_CACHE is-valid (bad .features)" fail is-valid "$cachedir" +remove_cachedir +runchecktest "AA_POLICY_CACHE is-valid (no cachedir)" fail is-valid "$cachedir" + +create_cachedir +install_bad_features_file +runchecktest "AA_POLICY_CACHE create (bad .features)" pass create "$cachedir" +runchecktest "AA_POLICY_CACHE create (good .features)" pass create "$cachedir" +remove_features_file +runchecktest "AA_POLICY_CACHE create (no .features)" fail create "$cachedir" +remove_cachedir +runchecktest "AA_POLICY_CACHE create (no cachedir)" fail create "$cachedir" + +# Make sure that no test policies are already loaded +verify_policies_are_not_loaded + +runchecktest "AA_POLICY_CACHE replace-all (no cachedir)" fail replace-all "$cachedir" +create_cachedir +runchecktest "AA_POLICY_CACHE replace-all (no .features)" fail replace-all "$cachedir" +create_empty_cache +runchecktest "AA_POLICY_CACHE replace-all (empty cache)" pass replace-all "$cachedir" +create_cache_files +runchecktest "AA_POLICY_CACHE replace-all (full cache)" pass replace-all "$cachedir" + +# Test that the previous policy load was successful +runchecktest_policies_are_loaded + +runchecktest "AA_POLICY_CACHE remove-policy (DNE)" fail remove-policy "aa_policy_cache_test_DNE" +runchecktest_remove_policies + +runchecktest "AA_POLICY_CACHE remove (full cache)" pass remove "$cachedir" +runchecktest "AA_POLICY_CACHE remove (no .features)" pass remove "$cachedir" +install_bad_features_file +runchecktest "AA_POLICY_CACHE remove (empty cache)" pass remove "$cachedir" +remove_cachedir +runchecktest "AA_POLICY_CACHE remove (DNE)" fail remove "$cachedir"