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:
Georgia Garcia 2023-03-29 14:45:48 -03:00
parent 50dd41f920
commit feb5069f67
5 changed files with 310 additions and 0 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -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 \

View 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;
}

View 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

View file

@ -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);
} }