forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add tests for filesystem kfuncs
Add selftests for two new filesystem kfuncs: 1. bpf_get_file_xattr 2. bpf_get_fsverity_digest These tests simply make sure the two kfuncs work. Another selftest will be added to demonstrate how to use these kfuncs to verify file signature. CONFIG_FS_VERITY is added to selftests config. However, this is not sufficient to guarantee bpf_get_fsverity_digest works. This is because fsverity need to be enabled at file system level (for example, with tune2fs on ext4). If local file system doesn't have this feature enabled, just skip the test. Signed-off-by: Song Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
- Loading branch information
1 parent
6b0ae45
commit 341f06f
Showing
5 changed files
with
223 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// 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_fsverity.skel.h" | ||
|
||
static const char testfile[] = "/tmp/test_progs_fs_kfuncs"; | ||
|
||
static void test_xattr(void) | ||
{ | ||
struct test_get_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; | ||
|
||
err = setxattr(testfile, "user.kfuncs", "hello", sizeof("hello"), 0); | ||
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; | ||
|
||
ASSERT_EQ(skel->bss->found_xattr, 1, "found_xattr"); | ||
|
||
out: | ||
close(fd); | ||
test_get_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) | ||
{ | ||
if (test__start_subtest("xattr")) | ||
test_xattr(); | ||
|
||
if (test__start_subtest("fsverity")) | ||
test_fsverity(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ | ||
|
||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include "bpf_kfuncs.h" | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
#ifndef SHA256_DIGEST_SIZE | ||
#define SHA256_DIGEST_SIZE 32 | ||
#endif | ||
|
||
#define SIZEOF_STRUCT_FSVERITY_DIGEST 4 /* sizeof(struct fsverity_digest) */ | ||
|
||
char expected_digest[SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; | ||
char digest[SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; | ||
__u32 monitored_pid; | ||
__u32 got_fsverity; | ||
__u32 digest_matches; | ||
|
||
SEC("lsm.s/file_open") | ||
int BPF_PROG(test_file_open, struct file *f) | ||
{ | ||
struct bpf_dynptr digest_ptr; | ||
__u32 pid; | ||
int ret; | ||
int i; | ||
|
||
pid = bpf_get_current_pid_tgid() >> 32; | ||
if (pid != monitored_pid) | ||
return 0; | ||
|
||
bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); | ||
ret = bpf_get_fsverity_digest(f, &digest_ptr); | ||
if (ret < 0) | ||
return 0; | ||
got_fsverity = 1; | ||
|
||
for (i = 0; i < sizeof(digest); i++) { | ||
if (digest[i] != expected_digest[i]) | ||
return 0; | ||
} | ||
|
||
digest_matches = 1; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ | ||
|
||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include "bpf_kfuncs.h" | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
__u32 monitored_pid; | ||
__u32 found_xattr; | ||
|
||
static const char expected_value[] = "hello"; | ||
char value[32]; | ||
|
||
SEC("lsm.s/file_open") | ||
int BPF_PROG(test_file_open, struct file *f) | ||
{ | ||
struct bpf_dynptr value_ptr; | ||
__u32 pid; | ||
int ret; | ||
|
||
pid = bpf_get_current_pid_tgid() >> 32; | ||
if (pid != monitored_pid) | ||
return 0; | ||
|
||
bpf_dynptr_from_mem(value, sizeof(value), 0, &value_ptr); | ||
|
||
ret = bpf_get_file_xattr(f, "user.kfuncs", &value_ptr); | ||
if (ret != sizeof(expected_value)) | ||
return 0; | ||
if (bpf_strncmp(value, ret, expected_value)) | ||
return 0; | ||
found_xattr = 1; | ||
return 0; | ||
} |