// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <linux/fsverity.h>
#include <unistd.h>
#include <test_progs.h>
#include "test_get_xattr.skel.h"
#include "test_set_remove_xattr.skel.h"
#include "test_fsverity.skel.h"
static const char testfile[] = "/tmp/test_progs_fs_kfuncs" ;
static void test_get_xattr(const char *name, const char *value, bool allow_access)
{
struct test_get_xattr *skel = NULL;
int fd = -1 , err;
int v[32 ];
fd = open(testfile, O_CREAT | O_RDONLY, 0644 );
if (!ASSERT_GE(fd, 0 , "create_file" ))
return ;
close(fd);
fd = -1 ;
err = setxattr(testfile, name, value, strlen(value) + 1 , 0 );
if (err && errno == EOPNOTSUPP) {
printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
"To run this test, make sure /tmp filesystem supports xattr.\n" ,
__func__, errno);
test__skip();
goto out;
}
if (!ASSERT_OK(err, "setxattr" ))
goto out;
skel = test_get_xattr__open_and_load();
if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load" ))
goto out;
skel->bss->monitored_pid = getpid();
err = test_get_xattr__attach(skel);
if (!ASSERT_OK(err, "test_get_xattr__attach" ))
goto out;
fd = open(testfile, O_RDONLY, 0644 );
if (!ASSERT_GE(fd, 0 , "open_file" ))
goto out;
/* Trigger security_inode_getxattr */
err = getxattr(testfile, name, v, sizeof (v));
if (allow_access) {
ASSERT_EQ(err, -1 , "getxattr_return" );
ASSERT_EQ(errno, EINVAL, "getxattr_errno" );
ASSERT_EQ(skel->bss->found_xattr_from_file, 1 , "found_xattr_from_file" );
ASSERT_EQ(skel->bss->found_xattr_from_dentry, 1 , "found_xattr_from_dentry" );
} else {
ASSERT_EQ(err, strlen(value) + 1 , "getxattr_return" );
ASSERT_EQ(skel->bss->found_xattr_from_file, 0 , "found_xattr_from_file" );
ASSERT_EQ(skel->bss->found_xattr_from_dentry, 0 , "found_xattr_from_dentry" );
}
out:
close(fd);
test_get_xattr__destroy(skel);
remove(testfile);
}
/* xattr value we will set to security.bpf.foo */
static const char value_foo[] = "hello" ;
static void read_and_validate_foo(struct test_set_remove_xattr *skel)
{
char value_out[32 ];
int err;
err = getxattr(testfile, skel->rodata->xattr_foo, value_out, sizeof (value_out));
ASSERT_EQ(err, sizeof (value_foo), "getxattr size foo" );
ASSERT_EQ(strncmp(value_out, value_foo, sizeof (value_foo)), 0 , "strncmp value_foo" );
}
static void set_foo(struct test_set_remove_xattr *skel)
{
ASSERT_OK(setxattr(testfile, skel->rodata->xattr_foo, value_foo, strlen(value_foo) + 1 , 0 ),
"setxattr foo" );
}
static void validate_bar_match(struct test_set_remove_xattr *skel)
{
char value_out[32 ];
int err;
err = getxattr(testfile, skel->rodata->xattr_bar, value_out, sizeof (value_out));
ASSERT_EQ(err, sizeof (skel->data->value_bar), "getxattr size bar" );
ASSERT_EQ(strncmp(value_out, skel->data->value_bar, sizeof (skel->data->value_bar)), 0 ,
"strncmp value_bar" );
}
static void validate_bar_removed(struct test_set_remove_xattr *skel)
{
char value_out[32 ];
int err;
err = getxattr(testfile, skel->rodata->xattr_bar, value_out, sizeof (value_out));
ASSERT_LT(err, 0 , "getxattr size bar should fail" );
}
static void test_set_remove_xattr(void )
{
struct test_set_remove_xattr *skel = NULL;
int fd = -1 , err;
fd = open(testfile, O_CREAT | O_RDONLY, 0644 );
if (!ASSERT_GE(fd, 0 , "create_file" ))
return ;
close(fd);
fd = -1 ;
skel = test_set_remove_xattr__open_and_load();
if (!ASSERT_OK_PTR(skel, "test_set_remove_xattr__open_and_load" ))
return ;
/* Set security.bpf.foo to "hello" */
err = setxattr(testfile, skel->rodata->xattr_foo, value_foo, strlen(value_foo) + 1 , 0 );
if (err && errno == EOPNOTSUPP) {
printf("%s:SKIP:local fs doesn't support xattr (%d)\n"
"To run this test, make sure /tmp filesystem supports xattr.\n" ,
__func__, errno);
test__skip();
goto out;
}
if (!ASSERT_OK(err, "setxattr" ))
goto out;
skel->bss->monitored_pid = getpid();
err = test_set_remove_xattr__attach(skel);
if (!ASSERT_OK(err, "test_set_remove_xattr__attach" ))
goto out;
/* First, test not _locked version of the kfuncs with getxattr. */
/* Read security.bpf.foo and trigger test_inode_getxattr. This
* bpf program will set security . bpf . bar to " world " .
*/
read_and_validate_foo(skel);
validate_bar_match(skel);
/* Read security.bpf.foo and trigger test_inode_getxattr again.
* This will remove xattr security . bpf . bar .
*/
read_and_validate_foo(skel);
validate_bar_removed(skel);
ASSERT_TRUE(skel->bss->set_security_bpf_bar_success, "set_security_bpf_bar_success" );
ASSERT_TRUE(skel->bss->remove_security_bpf_bar_success, "remove_security_bpf_bar_success" );
ASSERT_TRUE(skel->bss->set_security_selinux_fail, "set_security_selinux_fail" );
ASSERT_TRUE(skel->bss->remove_security_selinux_fail, "remove_security_selinux_fail" );
/* Second, test _locked version of the kfuncs, with setxattr */
/* Set security.bpf.foo and trigger test_inode_setxattr. This
* bpf program will set security . bpf . bar to " world " .
*/
set_foo(skel);
validate_bar_match(skel);
/* Set security.bpf.foo and trigger test_inode_setxattr again.
* This will remove xattr security . bpf . bar .
*/
set_foo(skel);
validate_bar_removed(skel);
ASSERT_TRUE(skel->bss->locked_set_security_bpf_bar_success,
"locked_set_security_bpf_bar_success" );
ASSERT_TRUE(skel->bss->locked_remove_security_bpf_bar_success,
"locked_remove_security_bpf_bar_success" );
ASSERT_TRUE(skel->bss->locked_set_security_selinux_fail,
"locked_set_security_selinux_fail" );
ASSERT_TRUE(skel->bss->locked_remove_security_selinux_fail,
"locked_remove_security_selinux_fail" );
out:
close(fd);
test_set_remove_xattr__destroy(skel);
remove(testfile);
}
#ifndef SHA256_DIGEST_SIZE
#define SHA256_DIGEST_SIZE 32
#endif
static void test_fsverity(void )
{
struct fsverity_enable_arg arg = {0 };
struct test_fsverity *skel = NULL;
struct fsverity_digest *d;
int fd, err;
char buffer[4096 ];
fd = open(testfile, O_CREAT | O_RDWR, 0644 );
if (!ASSERT_GE(fd, 0 , "create_file" ))
return ;
/* Write random buffer, so the file is not empty */
err = write(fd, buffer, 4096 );
if (!ASSERT_EQ(err, 4096 , "write_file" ))
goto out;
close(fd);
/* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */
fd = open(testfile, O_RDONLY, 0644 );
if (!ASSERT_GE(fd, 0 , "open_file1" ))
return ;
/* Enable fsverity for the file.
* If the file system doesn ' t support verity , this will fail . Skip
* the test in such case .
*/
arg.version = 1 ;
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
arg.block_size = 4096 ;
err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg);
if (err) {
printf("%s:SKIP:local fs doesn't support fsverity (%d)\n"
"To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n" ,
__func__, errno);
test__skip();
goto out;
}
skel = test_fsverity__open_and_load();
if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load" ))
goto out;
/* Get fsverity_digest from ioctl */
d = (struct fsverity_digest *)skel->bss->expected_digest;
d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256;
d->digest_size = SHA256_DIGEST_SIZE;
err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest);
if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY" ))
goto out;
skel->bss->monitored_pid = getpid();
err = test_fsverity__attach(skel);
if (!ASSERT_OK(err, "test_fsverity__attach" ))
goto out;
/* Reopen the file to trigger the program */
close(fd);
fd = open(testfile, O_RDONLY);
if (!ASSERT_GE(fd, 0 , "open_file2" ))
goto out;
ASSERT_EQ(skel->bss->got_fsverity, 1 , "got_fsverity" );
ASSERT_EQ(skel->bss->digest_matches, 1 , "digest_matches" );
out:
close(fd);
test_fsverity__destroy(skel);
remove(testfile);
}
void test_fs_kfuncs(void )
{
/* Matches xattr_names in progs/test_get_xattr.c */
if (test__start_subtest("user_xattr" ))
test_get_xattr("user.kfuncs" , "hello" , true );
if (test__start_subtest("security_bpf_xattr" ))
test_get_xattr("security.bpf.xxx" , "hello" , true );
if (test__start_subtest("security_bpf_xattr_error" ))
test_get_xattr("security.bpf" , "hello" , false );
if (test__start_subtest("security_selinux_xattr_error" ))
test_get_xattr("security.selinux" , "hello" , false );
if (test__start_subtest("set_remove_xattr" ))
test_set_remove_xattr();
if (test__start_subtest("fsverity" ))
test_fsverity();
}
Messung V0.5 in Prozent C=95 H=75 G=85
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland