From 0727da47b3e2ec1e66b7f349bced82c1e6674c94 Mon Sep 17 00:00:00 2001 From: Georgia Garcia Date: Fri, 4 Nov 2022 08:29:45 +0000 Subject: [PATCH] tests: add userns regression tests Signed-off-by: Georgia Garcia --- .gitignore | 1 + tests/regression/apparmor/Makefile | 2 + tests/regression/apparmor/mkprofile.pl | 16 ++++ tests/regression/apparmor/userns.c | 59 +++++++++++++ tests/regression/apparmor/userns.sh | 114 +++++++++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 tests/regression/apparmor/userns.c create mode 100755 tests/regression/apparmor/userns.sh diff --git a/.gitignore b/.gitignore index f0ee4dfbc..f6c66862b 100644 --- a/.gitignore +++ b/.gitignore @@ -295,6 +295,7 @@ tests/regression/apparmor/unix_fd_server tests/regression/apparmor/unix_socket tests/regression/apparmor/unix_socket_client tests/regression/apparmor/unlink +tests/regression/apparmor/userns tests/regression/apparmor/uservars.inc tests/regression/apparmor/xattrs tests/regression/apparmor/xattrs_profile diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile index ee392cd4f..d035cf14c 100644 --- a/tests/regression/apparmor/Makefile +++ b/tests/regression/apparmor/Makefile @@ -142,6 +142,7 @@ SRC=access.c \ unix_socket.c \ unix_socket_client.c \ unlink.c \ + userns.c \ xattrs.c \ xattrs_profile.c @@ -255,6 +256,7 @@ TESTS=aa_exec \ unix_socket_unnamed \ unix_socket_autobind \ unlink\ + userns\ xattrs\ xattrs_profile\ longpath \ diff --git a/tests/regression/apparmor/mkprofile.pl b/tests/regression/apparmor/mkprofile.pl index 201d53cb5..a823b70ed 100755 --- a/tests/regression/apparmor/mkprofile.pl +++ b/tests/regression/apparmor/mkprofile.pl @@ -309,6 +309,20 @@ sub gen_pivot_root($) { } } +sub gen_userns($) { + my $rule = shift; + my @rules = split (/:/, $rule); + if (@rules == 2) { + if ($rules[1] =~ /^ALL$/) { + push (@{$output_rules{$hat}}, " userns,\n"); + } else { + push (@{$output_rules{$hat}}, " userns $rules[1],\n"); + } + } else { + (!$nowarn) && print STDERR "Warning: invalid userns description '$rule', ignored\n"; + } +} + sub gen_file($) { my $rule = shift; my @rules = split (/:/, $rule); @@ -450,6 +464,8 @@ sub gen_from_args() { gen_umount($rule); } elsif ($rule =~ /^pivot_root:/) { gen_pivot_root($rule); + } elsif ($rule =~ /^userns:/) { + gen_userns($rule) } elsif ($rule =~ /^flag:/) { gen_flag($rule); } elsif ($rule =~ /^hat:/) { diff --git a/tests/regression/apparmor/userns.c b/tests/regression/apparmor/userns.c new file mode 100644 index 000000000..a0959b60b --- /dev/null +++ b/tests/regression/apparmor/userns.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +static int child(void *arg) +{ + printf("PASS\n"); + return EXIT_SUCCESS; +} + +#define STACK_SIZE (1024 * 1024) +static char child_stack[STACK_SIZE]; + +int main(int argc, char *argv[]) +{ + pid_t child_pid; + int child_exit; + + child_pid = clone(child, child_stack + STACK_SIZE, + CLONE_NEWUSER | SIGCHLD, NULL); + if (child_pid == -1) { + perror("FAIL - clone"); + return EXIT_FAILURE; + } + + if (waitpid(child_pid, &child_exit, 0) == -1) { + perror("FAIL - waitpid"); + return EXIT_FAILURE; + } + + if (WIFEXITED(child_exit)) { + if (WEXITSTATUS(child_exit) != EXIT_SUCCESS) { + fprintf(stderr, "FAIL - child ended with failure %d\n", child_exit); + return EXIT_FAILURE; + } + } + + printf("PASS\n"); + return EXIT_SUCCESS; +} diff --git a/tests/regression/apparmor/userns.sh b/tests/regression/apparmor/userns.sh new file mode 100755 index 000000000..ac887a22d --- /dev/null +++ b/tests/regression/apparmor/userns.sh @@ -0,0 +1,114 @@ +#! /bin/bash +#Copyright (C) 2022 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 userns +#=DESCRIPTION +# This test verifies if mediation of user namespaces is working +#=END + +pwd=`dirname $0` +pwd=`cd $pwd ; /bin/pwd` + +bin=$pwd + +. $bin/prologue.inc + +requires_kernel_features namespaces/mask/userns_create +requires_parser_support "userns," + +apparmor_restrict_unprivileged_userns_path=/proc/sys/kernel/apparmor_restrict_unprivileged_userns +if [ ! -e $apparmor_restrict_unprivileged_userns_path ]; then + echo "$apparmor_restrict_unprivileged_userns_path not available. Skipping tests ..." + exit 0 +fi + +apparmor_restrict_unprivileged_userns=$(cat $apparmor_restrict_unprivileged_userns_path) + +unprivileged_userns_clone_path=/proc/sys/kernel/unprivileged_userns_clone +if [ -e $unprivileged_userns_clone_path ]; then + unprivileged_userns_clone=$(cat $unprivileged_userns_clone_path) +fi + +restore_userns() +{ + echo $apparmor_restrict_unprivileged_userns > $apparmor_restrict_unprivileged_userns_path +} +do_onexit="restore_userns" + +do_test() +{ + local desc="USERNS ($1)" + expect_root=$2 + expect_user=$3 + generate_profile=$4 + + settest userns + $generate_profile # settest removes the profile, so load it here + runchecktest "$desc - root" $expect_root + + settest -u "foo" userns # run tests as user foo + $generate_profile # settest removes the profile, so load it here + runchecktest "$desc - user" $expect_user +} + +if [ $unprivileged_userns_clone -eq 0 ]; then + echo "WARN: unprivileged_userns_clone is enabled. Both confined and unconfined unprivileged user namespaces are not allowed" + + detail="unprivileged_userns_clone disabled" + do_test "unconfined - $detail" pass fail + + generate_profile="genprofile userns cap:sys_admin" + do_test "confined all perms $detail" pass fail "$generate_profile" + + generate_profile="genprofile cap:sys_admin" + do_test "confined no perms $detail" fail fail "$generate_profile" + + generate_profile="genprofile userns:create cap:sys_admin" + do_test "confined specific perms $detail" pass fail "$generate_profile" + + exit 0 +fi + + +# confined tests should have the same results if apparmor_restrict_unprivileged_userns is enabled or not +run_confined_tests() +{ + generate_profile="genprofile userns" + do_test "confined all perms $1" pass pass "$generate_profile" + + generate_profile="genprofile" + do_test "confined no perms $1" fail fail "$generate_profile" + + generate_profile="genprofile userns:create" + do_test "confined specific perms $1" pass pass "$generate_profile" +} + +# ---------------------------------------------------- +# disable restrictions on unprivileged user namespaces +echo 0 > $apparmor_restrict_unprivileged_userns_path + +detail="apparmor_restrict_unprivileged_userns disabled" +do_test "unconfined - $detail" pass pass + +run_confined_tests "$detail" + +# ---------------------------------------------------- +# enable restrictions on unprivileged user namespaces +echo 1 > $apparmor_restrict_unprivileged_userns_path + +detail="apparmor_restrict_unprivileged_userns enabled" +# user cannot create user namespace unless cap_sys_admin +do_test "unconfined $detail" pass fail + +# it should work when running as user with cap_sys_admin +setcap cap_sys_admin+pie $bin/userns +do_test "unconfined cap_sys_admin $detail" pass pass +# remove cap_sys_admin from binary +setcap cap_sys_admin= $bin/userns + +run_confined_tests "$detail"