mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
tests: add io_uring regression tests
Note that the tests add the dependency of liburing. Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
This commit is contained in:
parent
50dd41f920
commit
feb5069f67
5 changed files with 310 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -256,6 +256,7 @@ tests/regression/apparmor/fd_inheritance
|
||||||
tests/regression/apparmor/fd_inheritor
|
tests/regression/apparmor/fd_inheritor
|
||||||
tests/regression/apparmor/fork
|
tests/regression/apparmor/fork
|
||||||
tests/regression/apparmor/introspect
|
tests/regression/apparmor/introspect
|
||||||
|
tests/regression/apparmor/io_uring
|
||||||
tests/regression/apparmor/link
|
tests/regression/apparmor/link
|
||||||
tests/regression/apparmor/link_subset
|
tests/regression/apparmor/link_subset
|
||||||
tests/regression/apparmor/mkdir
|
tests/regression/apparmor/mkdir
|
||||||
|
|
|
@ -104,6 +104,7 @@ SRC=access.c \
|
||||||
fd_inheritance.c \
|
fd_inheritance.c \
|
||||||
fd_inheritor.c \
|
fd_inheritor.c \
|
||||||
fork.c \
|
fork.c \
|
||||||
|
io_uring.c \
|
||||||
link.c \
|
link.c \
|
||||||
link_subset.c \
|
link_subset.c \
|
||||||
mmap.c \
|
mmap.c \
|
||||||
|
@ -354,6 +355,9 @@ userns_setns: userns_setns.c userns.h
|
||||||
mount: mount.c
|
mount: mount.c
|
||||||
${CC} ${CFLAGS} -std=gnu99 ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
${CC} ${CFLAGS} -std=gnu99 ${LDFLAGS} $^ -o $@ ${LDLIBS}
|
||||||
|
|
||||||
|
io_uring: io_uring.c
|
||||||
|
${CC} ${CFLAGS} ${LDFLAGS} $< -o $@ ${LDLIBS} -luring
|
||||||
|
|
||||||
build-dep:
|
build-dep:
|
||||||
@if [ `whoami` = "root" ] ;\
|
@if [ `whoami` = "root" ] ;\
|
||||||
then \
|
then \
|
||||||
|
|
204
tests/regression/apparmor/io_uring.c
Normal file
204
tests/regression/apparmor/io_uring.c
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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 <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <liburing.h>
|
||||||
|
|
||||||
|
#define DEFAULT_FILENAME "/tmp/io_uring_test"
|
||||||
|
#define DEFAULT_UID 1000
|
||||||
|
|
||||||
|
static int no_personality;
|
||||||
|
|
||||||
|
static int open_file(struct io_uring *ring, int cred_id, char *filename)
|
||||||
|
{
|
||||||
|
struct io_uring_cqe *cqe;
|
||||||
|
struct io_uring_sqe *sqe;
|
||||||
|
int ret, i, to_submit = 1;
|
||||||
|
|
||||||
|
sqe = io_uring_get_sqe(ring);
|
||||||
|
if (!sqe) {
|
||||||
|
fprintf(stderr, "FAIL - could not get sqe.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
io_uring_prep_openat(sqe, -1, filename, O_RDONLY, 0);
|
||||||
|
sqe->user_data = 1;
|
||||||
|
|
||||||
|
if (cred_id != -1)
|
||||||
|
sqe->personality = cred_id;
|
||||||
|
|
||||||
|
ret = io_uring_submit(ring);
|
||||||
|
if (ret != to_submit) {
|
||||||
|
fprintf(stderr, "FAIL - could not submit: %s\n", strerror(-ret));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < to_submit; i++) {
|
||||||
|
ret = io_uring_wait_cqe(ring, &cqe);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "FAIL - wait cqe failed %s\n", strerror(-ret));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cqe->res;
|
||||||
|
io_uring_cqe_seen(ring, cqe);
|
||||||
|
}
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_personality(struct io_uring *ring, char *filename, uid_t uid)
|
||||||
|
{
|
||||||
|
int ret, cred_id;
|
||||||
|
ret = io_uring_register_personality(ring);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (ret == -EINVAL) {
|
||||||
|
no_personality = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "FAIL - could not register personality: %s\n", strerror(-ret));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
cred_id = ret;
|
||||||
|
|
||||||
|
/* create file only owner can open */
|
||||||
|
ret = open(filename, O_RDONLY | O_CREAT, 0600);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("open");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
close(ret);
|
||||||
|
|
||||||
|
/* verify we can open it */
|
||||||
|
ret = open_file(ring, -1, filename);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "FAIL - root could not open file: %d\n", ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seteuid(uid) < 0) {
|
||||||
|
fprintf(stdout, "FAIL - could not switch to uid %u\n", uid);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify we can't open it with current credentials */
|
||||||
|
ret = open_file(ring, -1, filename);
|
||||||
|
if (ret != -EACCES) {
|
||||||
|
fprintf(stderr, "FAIL - opened with regular credential: %d\n", ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify we can open with registered credentials */
|
||||||
|
ret = open_file(ring, cred_id, filename);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "FAIL - could not open with registered credentials: %d\n", ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
close(ret);
|
||||||
|
|
||||||
|
if (seteuid(0))
|
||||||
|
perror("FAIL - seteuid");
|
||||||
|
|
||||||
|
ret = io_uring_unregister_personality(ring, cred_id);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "FAIL - could not unregister personality: %s\n",
|
||||||
|
strerror(-ret));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
unlink(filename);
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
unlink(filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(char *pname)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s [options]\n", pname);
|
||||||
|
fprintf(stderr, "Options can be:\n");
|
||||||
|
fprintf(stderr, " -s create ring using IORING_SETUP_SQPOLL\n");
|
||||||
|
fprintf(stderr, " -o use io_uring personality to open a file\n");
|
||||||
|
fprintf(stderr, " -u specify UID for option -s (default is %d)\n", DEFAULT_UID);
|
||||||
|
fprintf(stderr, " -f specify file opened by option -s (default is %s)\n", DEFAULT_FILENAME);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum op {
|
||||||
|
SQPOLL,
|
||||||
|
OVERRIDE_CREDS,
|
||||||
|
INVALID_OP,
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct io_uring ring;
|
||||||
|
int opt, ret = 0, op = INVALID_OP;
|
||||||
|
char *filename = DEFAULT_FILENAME;
|
||||||
|
uid_t uid = DEFAULT_UID;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "sou:f:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 's': op = SQPOLL; break;
|
||||||
|
case 'o': op = OVERRIDE_CREDS; break;
|
||||||
|
case 'u': uid = atoi(optarg); break;
|
||||||
|
case 'f': filename = optarg; break;
|
||||||
|
default: usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == INVALID_OP) {
|
||||||
|
printf("FAIL - operation not selected\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == SQPOLL) {
|
||||||
|
ret = io_uring_queue_init(8, &ring, IORING_SETUP_SQPOLL);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "FAIL - failed to create sqpoll ring: %s\n",
|
||||||
|
strerror(-ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
io_uring_queue_exit(&ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == OVERRIDE_CREDS) {
|
||||||
|
ret = io_uring_queue_init(8, &ring, 0);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "FAIL - failed to create override_creds ring: %s\n",
|
||||||
|
strerror(-ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = test_personality(&ring, filename, uid);
|
||||||
|
if (no_personality) {
|
||||||
|
/* personality was added in kernel 5.6 */
|
||||||
|
printf("Personalities not supported, skipping...\n");
|
||||||
|
} else if (ret) {
|
||||||
|
fprintf(stderr, "FAIL - override_creds failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
io_uring_queue_exit(&ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("PASS\n");
|
||||||
|
return 0;
|
||||||
|
}
|
83
tests/regression/apparmor/io_uring.sh
Executable file
83
tests/regression/apparmor/io_uring.sh
Executable file
|
@ -0,0 +1,83 @@
|
||||||
|
#! /bin/bash
|
||||||
|
#Copyright (C) 2023 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 io_uring
|
||||||
|
#=DESCRIPTION
|
||||||
|
# This test verifies if mediation of io_uring is working
|
||||||
|
#=END
|
||||||
|
|
||||||
|
pwd=`dirname $0`
|
||||||
|
pwd=`cd $pwd ; /bin/pwd`
|
||||||
|
|
||||||
|
bin=$pwd
|
||||||
|
|
||||||
|
. $bin/prologue.inc
|
||||||
|
|
||||||
|
requires_kernel_features io_uring
|
||||||
|
requires_parser_support "io_uring,"
|
||||||
|
|
||||||
|
settest io_uring
|
||||||
|
|
||||||
|
uid=1000
|
||||||
|
file=$tmpdir/io_uring_test
|
||||||
|
label=$bin/io_uring
|
||||||
|
|
||||||
|
required_perms="$file:rw cap:setuid cap:ipc_lock"
|
||||||
|
|
||||||
|
do_test()
|
||||||
|
{
|
||||||
|
local desc="IO_URING ($1)"
|
||||||
|
shift
|
||||||
|
runchecktest "$desc" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_tests()
|
||||||
|
{
|
||||||
|
prefix=$1
|
||||||
|
expect_sqpoll=$2
|
||||||
|
expect_override_creds=$3
|
||||||
|
|
||||||
|
do_test "$prefix - test sqpoll" $expect_sqpoll -s
|
||||||
|
do_test "$prefix - test override_creds" $expect_override_creds -o -u $uid -f $file
|
||||||
|
}
|
||||||
|
|
||||||
|
# make sure it works unconfined
|
||||||
|
do_tests "unconfined" pass pass
|
||||||
|
|
||||||
|
genprofile $required_perms
|
||||||
|
do_tests "no perms" fail fail
|
||||||
|
|
||||||
|
genprofile $required_perms "qual=deny:io_uring"
|
||||||
|
do_tests "deny perms" fail fail
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring"
|
||||||
|
do_tests "generic perms" pass pass
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:sqpoll"
|
||||||
|
do_tests "only sqpoll perm" pass fail
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:override_creds"
|
||||||
|
do_tests "only override_creds perm" fail pass
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:(sqpoll, override_creds)"
|
||||||
|
do_tests "explicit perms" pass pass
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:sqpoll:label=$label"
|
||||||
|
do_tests "specify label without override_creds perm" pass fail
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:label=$label"
|
||||||
|
do_tests "all perms specify label" pass pass
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:(sqpoll, override_creds):label=$label"
|
||||||
|
do_tests "specify perms specify label" pass pass
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:override_creds:label=$label"
|
||||||
|
do_tests "specify label" fail pass
|
||||||
|
|
||||||
|
genprofile $required_perms "io_uring:override_creds:label=/foo"
|
||||||
|
do_tests "invalid label" fail fail
|
|
@ -443,6 +443,22 @@ sub gen_mqueue($@) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub gen_io_uring($@) {
|
||||||
|
my ($rule, $qualifier) = @_;
|
||||||
|
my @rules = split (/:/, $rule);
|
||||||
|
if (@rules == 2) {
|
||||||
|
if ($rules[1] =~ /^ALL$/) {
|
||||||
|
push (@{$output_rules{$hat}}, " ${qualifier}io_uring,\n");
|
||||||
|
} else {
|
||||||
|
push (@{$output_rules{$hat}}, " ${qualifier}io_uring $rules[1],\n");
|
||||||
|
}
|
||||||
|
} elsif (@rules == 3) {
|
||||||
|
push (@{$output_rules{$hat}}, " ${qualifier}io_uring $rules[1] $rules[2],\n");
|
||||||
|
} else {
|
||||||
|
(!$nowarn) && print STDERR "Warning: invalid io_uring description '$rule', ignored\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub emit_flags($) {
|
sub emit_flags($) {
|
||||||
my $hat = shift;
|
my $hat = shift;
|
||||||
|
|
||||||
|
@ -514,6 +530,8 @@ sub gen_from_args() {
|
||||||
gen_path($rule);
|
gen_path($rule);
|
||||||
} elsif ($rule =~ /^mqueue:/) {
|
} elsif ($rule =~ /^mqueue:/) {
|
||||||
gen_mqueue($rule, $qualifier);
|
gen_mqueue($rule, $qualifier);
|
||||||
|
} elsif ($rule =~ /^io_uring:/) {
|
||||||
|
gen_io_uring($rule, $qualifier);
|
||||||
} else {
|
} else {
|
||||||
gen_file($rule, $qualifier);
|
gen_file($rule, $qualifier);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue