mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 11:33:28 +02:00
selftests/landlock: Test IOCTL support
Exercises Landlock's IOCTL feature in different combinations of handling and permitting the LANDLOCK_ACCESS_FS_IOCTL_DEV right, and in different combinations of using files and directories. Signed-off-by: Günther Noack <gnoack@google.com> Link: https://lore.kernel.org/r/20240419161122.2023765-3-gnoack@google.com Signed-off-by: Mickaël Salaün <mic@digikod.net>
This commit is contained in:
parent
b25f7415eb
commit
3ecf19e568
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <asm/termbits.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/landlock.h>
|
||||
|
|
@ -16,6 +17,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/sendfile.h>
|
||||
|
|
@ -24,6 +26,12 @@
|
|||
#include <sys/vfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Intentionally included last to work around header conflict.
|
||||
* See https://sourceware.org/glibc/wiki/Synchronizing_Headers.
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifndef renameat2
|
||||
|
|
@ -744,6 +752,9 @@ static int create_ruleset(struct __test_metadata *const _metadata,
|
|||
}
|
||||
|
||||
for (i = 0; rules[i].path; i++) {
|
||||
if (!rules[i].access)
|
||||
continue;
|
||||
|
||||
add_path_beneath(_metadata, ruleset_fd, rules[i].access,
|
||||
rules[i].path);
|
||||
}
|
||||
|
|
@ -3452,7 +3463,7 @@ TEST_F_FORK(layout1, truncate_unhandled)
|
|||
LANDLOCK_ACCESS_FS_WRITE_FILE;
|
||||
int ruleset_fd;
|
||||
|
||||
/* Enable Landlock. */
|
||||
/* Enables Landlock. */
|
||||
ruleset_fd = create_ruleset(_metadata, handled, rules);
|
||||
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
|
|
@ -3535,7 +3546,7 @@ TEST_F_FORK(layout1, truncate)
|
|||
LANDLOCK_ACCESS_FS_TRUNCATE;
|
||||
int ruleset_fd;
|
||||
|
||||
/* Enable Landlock. */
|
||||
/* Enables Landlock. */
|
||||
ruleset_fd = create_ruleset(_metadata, handled, rules);
|
||||
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
|
|
@ -3761,7 +3772,7 @@ TEST_F_FORK(ftruncate, open_and_ftruncate)
|
|||
};
|
||||
int fd, ruleset_fd;
|
||||
|
||||
/* Enable Landlock. */
|
||||
/* Enables Landlock. */
|
||||
ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
|
|
@ -3854,6 +3865,181 @@ TEST(memfd_ftruncate)
|
|||
ASSERT_EQ(0, close(fd));
|
||||
}
|
||||
|
||||
static int test_fionread_ioctl(int fd)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
if (ioctl(fd, FIONREAD, &sz) < 0 && errno == EACCES)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE(ioctl) {};
|
||||
|
||||
FIXTURE_SETUP(ioctl) {};
|
||||
|
||||
FIXTURE_TEARDOWN(ioctl) {};
|
||||
/* clang-format on */
|
||||
|
||||
FIXTURE_VARIANT(ioctl)
|
||||
{
|
||||
const __u64 handled;
|
||||
const __u64 allowed;
|
||||
const mode_t open_mode;
|
||||
/*
|
||||
* FIONREAD is used as a characteristic device-specific IOCTL command.
|
||||
* It is implemented in fs/ioctl.c for regular files,
|
||||
* but we do not blanket-permit it for devices.
|
||||
*/
|
||||
const int expected_fionread_result;
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_none) {
|
||||
/* clang-format on */
|
||||
.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
.allowed = 0,
|
||||
.open_mode = O_RDWR,
|
||||
.expected_fionread_result = EACCES,
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(ioctl, handled_i_allowed_i) {
|
||||
/* clang-format on */
|
||||
.handled = LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
.allowed = LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
.open_mode = O_RDWR,
|
||||
.expected_fionread_result = 0,
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(ioctl, unhandled) {
|
||||
/* clang-format on */
|
||||
.handled = LANDLOCK_ACCESS_FS_EXECUTE,
|
||||
.allowed = LANDLOCK_ACCESS_FS_EXECUTE,
|
||||
.open_mode = O_RDWR,
|
||||
.expected_fionread_result = 0,
|
||||
};
|
||||
|
||||
TEST_F_FORK(ioctl, handle_dir_access_file)
|
||||
{
|
||||
const int flag = 0;
|
||||
const struct rule rules[] = {
|
||||
{
|
||||
.path = "/dev",
|
||||
.access = variant->allowed,
|
||||
},
|
||||
{},
|
||||
};
|
||||
int file_fd, ruleset_fd;
|
||||
|
||||
/* Enables Landlock. */
|
||||
ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
ASSERT_EQ(0, close(ruleset_fd));
|
||||
|
||||
file_fd = open("/dev/zero", variant->open_mode);
|
||||
ASSERT_LE(0, file_fd);
|
||||
|
||||
/* Checks that IOCTL commands return the expected errors. */
|
||||
EXPECT_EQ(variant->expected_fionread_result,
|
||||
test_fionread_ioctl(file_fd));
|
||||
|
||||
/* Checks that unrestrictable commands are unrestricted. */
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
|
||||
|
||||
ASSERT_EQ(0, close(file_fd));
|
||||
}
|
||||
|
||||
TEST_F_FORK(ioctl, handle_dir_access_dir)
|
||||
{
|
||||
const int flag = 0;
|
||||
const struct rule rules[] = {
|
||||
{
|
||||
.path = "/dev",
|
||||
.access = variant->allowed,
|
||||
},
|
||||
{},
|
||||
};
|
||||
int dir_fd, ruleset_fd;
|
||||
|
||||
/* Enables Landlock. */
|
||||
ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
ASSERT_EQ(0, close(ruleset_fd));
|
||||
|
||||
/*
|
||||
* Ignore variant->open_mode for this test, as we intend to open a
|
||||
* directory. If the directory can not be opened, the variant is
|
||||
* infeasible to test with an opened directory.
|
||||
*/
|
||||
dir_fd = open("/dev", O_RDONLY);
|
||||
if (dir_fd < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Checks that IOCTL commands return the expected errors.
|
||||
* We do not use the expected values from the fixture here.
|
||||
*
|
||||
* When using IOCTL on a directory, no Landlock restrictions apply.
|
||||
*/
|
||||
EXPECT_EQ(0, test_fionread_ioctl(dir_fd));
|
||||
|
||||
/* Checks that unrestrictable commands are unrestricted. */
|
||||
EXPECT_EQ(0, ioctl(dir_fd, FIOCLEX));
|
||||
EXPECT_EQ(0, ioctl(dir_fd, FIONCLEX));
|
||||
EXPECT_EQ(0, ioctl(dir_fd, FIONBIO, &flag));
|
||||
EXPECT_EQ(0, ioctl(dir_fd, FIOASYNC, &flag));
|
||||
EXPECT_EQ(0, ioctl(dir_fd, FIGETBSZ, &flag));
|
||||
|
||||
ASSERT_EQ(0, close(dir_fd));
|
||||
}
|
||||
|
||||
TEST_F_FORK(ioctl, handle_file_access_file)
|
||||
{
|
||||
const int flag = 0;
|
||||
const struct rule rules[] = {
|
||||
{
|
||||
.path = "/dev/zero",
|
||||
.access = variant->allowed,
|
||||
},
|
||||
{},
|
||||
};
|
||||
int file_fd, ruleset_fd;
|
||||
|
||||
/* Enables Landlock. */
|
||||
ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
ASSERT_EQ(0, close(ruleset_fd));
|
||||
|
||||
file_fd = open("/dev/zero", variant->open_mode);
|
||||
ASSERT_LE(0, file_fd)
|
||||
{
|
||||
TH_LOG("Failed to open /dev/zero: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Checks that IOCTL commands return the expected errors. */
|
||||
EXPECT_EQ(variant->expected_fionread_result,
|
||||
test_fionread_ioctl(file_fd));
|
||||
|
||||
/* Checks that unrestrictable commands are unrestricted. */
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIOCLEX));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIONCLEX));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag));
|
||||
EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag));
|
||||
|
||||
ASSERT_EQ(0, close(file_fd));
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE(layout1_bind) {};
|
||||
/* clang-format on */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user