mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
tests: Add NO_NEW_PRIVS regression tests
Test the profile transition limits imposed by NO_NEW_PRIVS to ensure that behavior doesn't unexpectedly change. Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
This commit is contained in:
parent
db1f391844
commit
9160204008
3 changed files with 104 additions and 3 deletions
|
@ -171,7 +171,7 @@ ifdef USE_SYSTEM
|
|||
endif
|
||||
|
||||
ifneq (,$(shell pkg-config --atleast-version 2.10.95 libapparmor && echo TRUE))
|
||||
CONDITIONAL_TESTS+=exec_stack stackonexec stackprofile
|
||||
CONDITIONAL_TESTS+=exec_stack nnp stackonexec stackprofile
|
||||
else
|
||||
$(warning ${nl}\
|
||||
************************************************************************${nl}\
|
||||
|
@ -181,7 +181,7 @@ ifdef USE_SYSTEM
|
|||
endif
|
||||
else
|
||||
SRC+=aa_policy_cache.c
|
||||
CONDITIONAL_TESTS+=exec_stack aa_policy_cache stackonexec stackprofile
|
||||
CONDITIONAL_TESTS+=exec_stack aa_policy_cache nnp stackonexec stackprofile
|
||||
endif
|
||||
|
||||
EXEC=$(SRC:%.c=%)
|
||||
|
|
82
tests/regression/apparmor/nnp.sh
Executable file
82
tests/regression/apparmor/nnp.sh
Executable file
|
@ -0,0 +1,82 @@
|
|||
#! /bin/bash
|
||||
# Copyright (C) 2019 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 nnp
|
||||
#=DESCRIPTION
|
||||
# Verifies AppArmor interactions with NO_NEW_PRIVS
|
||||
#=END
|
||||
|
||||
pwd=`dirname $0`
|
||||
pwd=`cd $pwd ; /bin/pwd`
|
||||
|
||||
bin=$pwd
|
||||
|
||||
. $bin/prologue.inc
|
||||
|
||||
settest transition
|
||||
|
||||
file=$tmpdir/file
|
||||
okperm=rw
|
||||
|
||||
fileok="${file}:${okperm}"
|
||||
|
||||
getcon="/proc/*/attr/current:r"
|
||||
setcon="/proc/*/attr/current:w"
|
||||
setexec="/proc/*/attr/exec:w"
|
||||
|
||||
touch $file
|
||||
|
||||
# Verify file access by an unconfined process
|
||||
runchecktest "NNP (unconfined - no NNP)" pass -f "$file"
|
||||
runchecktest "NNP (unconfined - NNP)" pass -n -f "$file"
|
||||
|
||||
# Verify file access under simple confinement
|
||||
genprofile "$fileok" "$getcon"
|
||||
runchecktest "NNP (confined - no NNP)" pass -f "$file"
|
||||
runchecktest "NNP (confined - NNP)" pass -n -f "$file"
|
||||
|
||||
# Verify that NNP allows ix transitions
|
||||
genprofile image="$test" "$fileok" "$getcon"
|
||||
runchecktest "NNP (ix - no NNP)" pass -- "$test" -f "$file"
|
||||
runchecktest "NNP (ix - NNP)" pass -- "$test" -n -f "$file"
|
||||
|
||||
# Verify that NNP causes unconfined profile transition failures
|
||||
# NNP-induced failures will use EPERM rather than EACCES
|
||||
genprofile -I "$test":rux "$fileok"
|
||||
runchecktest "NNP (ux - no NNP)" pass -- "$test" -f "$file"
|
||||
runchecktest_errno EPERM "NNP (ux - NNP)" fail -n -- "$test" -f "$file"
|
||||
|
||||
# Verify that NNP causes discrete profile transition failures
|
||||
genprofile "$bin/open":px -- image="$bin/open" "$fileok"
|
||||
runchecktest "NNP (px - no NNP)" pass -- "$bin/open" "$file"
|
||||
runchecktest_errno EPERM "NNP (px - NNP)" fail -n -- "$bin/open" "$file"
|
||||
|
||||
# Verify that NNP causes change onexec failures
|
||||
genprofile "change_profile->":"$bin/open" "$setexec" -- image="$bin/open" "$fileok"
|
||||
runchecktest "NNP (change onexec - no NNP)" pass -O "$bin/open" -- "$bin/open" "$file"
|
||||
runchecktest_errno EPERM "NNP (change onexec - NNP)" fail -n -O "$bin/open" -- "$bin/open" "$file"
|
||||
|
||||
# Verify that NNP causes change profile failures
|
||||
genprofile "change_profile->":"$bin/open" "$setcon" -- image="$bin/open"
|
||||
runchecktest "NNP (change profile - no NNP)" pass -P "$bin/open"
|
||||
runchecktest_errno EPERM "NNP (change profile - NNP)" fail -n -P "$bin/open"
|
||||
|
||||
if [ "$(kernel_features_istrue domain/stack)" != "true" ] ; then
|
||||
echo " kernel does not support profile stacking - skipping stacking tests ..."
|
||||
else
|
||||
|
||||
# Verify that NNP allows stack onexec of another profile
|
||||
genprofile "$fileok" "$setexec" "change_profile->:&${bin}/open" -- image="$bin/open" "$fileok"
|
||||
runchecktest "NNP (stack onexec - no NNP)" pass -o "$bin/open" -- "$bin/open" "$file"
|
||||
runchecktest "NNP (stack onexec - NNP)" pass -n -o "$bin/open" -- "$bin/open" "$file"
|
||||
|
||||
# Verify that NNP allows stacking another profile
|
||||
genprofile "$fileok" "$setcon" "change_profile->:&$bin/open" -- image="$bin/open" "$fileok"
|
||||
runchecktest "NNP (stack profile - no NNP)" pass -p "$bin/open" -f "$file"
|
||||
runchecktest "NNP (stack profile - NNP)" pass -n -p "$bin/open" -f "$file"
|
||||
fi
|
|
@ -21,6 +21,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -281,6 +282,15 @@ static void handle_transition(int transition, const char *target)
|
|||
}
|
||||
}
|
||||
|
||||
static void set_no_new_privs(void)
|
||||
{
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
|
||||
int err = errno;
|
||||
perror("FAIL - prctl (PR_SET_NO_NEW_PRIVS)");
|
||||
exit(err);
|
||||
}
|
||||
}
|
||||
|
||||
static void exec(const char *prog, char **argv)
|
||||
{
|
||||
int err;
|
||||
|
@ -299,6 +309,7 @@ static void usage(const char *prog)
|
|||
" -P <LABEL>\tCall aa_change_profile(LABEL)\n"
|
||||
" -o <LABEL>\tCall aa_stack_onexec(LABEL)\n"
|
||||
" -p <LABEL>\tCall aa_stack_profile(LABEL)\n"
|
||||
" -n\t\tSet NO_NEW_PRIVS\n"
|
||||
" -L <LABEL>\tVerify that /proc/self/attr/exec contains LABEL\n"
|
||||
" -M <MODE>\tVerify that /proc/self/attr/exec contains MODE. Set to \"%s\" if a NULL mode is expected.\n"
|
||||
" -l <LABEL>\tVerify that /proc/self/attr/current contains LABEL\n"
|
||||
|
@ -320,6 +331,8 @@ struct options {
|
|||
int transition; /* CHANGE_PROFILE, STACK_ONEXEC, etc. */
|
||||
const char *target; /* The target label of the transition */
|
||||
|
||||
bool no_new_privs;
|
||||
|
||||
const char *exec;
|
||||
char **exec_argv;
|
||||
};
|
||||
|
@ -341,7 +354,7 @@ static void parse_opts(int argc, char **argv, struct options *opts)
|
|||
int o;
|
||||
|
||||
memset(opts, 0, sizeof(*opts));
|
||||
while ((o = getopt(argc, argv, "f:L:M:l:m:O:P:o:p:")) != -1) {
|
||||
while ((o = getopt(argc, argv, "f:L:M:l:m:nO:P:o:p:")) != -1) {
|
||||
switch (o) {
|
||||
case 'f': /* file */
|
||||
opts->file = optarg;
|
||||
|
@ -358,6 +371,9 @@ static void parse_opts(int argc, char **argv, struct options *opts)
|
|||
case 'm': /* expected current mode */
|
||||
opts->expected_current_mode = optarg;
|
||||
break;
|
||||
case 'n': /* NO_NEW_PRIVS */
|
||||
opts->no_new_privs = true;
|
||||
break;
|
||||
case 'O': /* aa_change_profile */
|
||||
set_transition(prog, opts, CHANGE_ONEXEC, optarg);
|
||||
break;
|
||||
|
@ -391,6 +407,9 @@ int main(int argc, char **argv)
|
|||
|
||||
parse_opts(argc, argv, &opts);
|
||||
|
||||
if (opts.no_new_privs)
|
||||
set_no_new_privs();
|
||||
|
||||
if (opts.transition)
|
||||
handle_transition(opts.transition, opts.target);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue