Skip to content

Commit

Permalink
selftests/bpf: Add tests for filesystem kfuncs
Browse files Browse the repository at this point in the history
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 <song@kernel.org>
Link: https://lore.kernel.org/r/20231129234417.856536-6-song@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
liu-song-6 authored and Alexei Starovoitov committed Dec 2, 2023
1 parent 6b0ae45 commit 341f06f
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 0 deletions.
3 changes: 3 additions & 0 deletions tools/testing/selftests/bpf/bpf_kfuncs.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,7 @@ void *bpf_cast_to_kern_ctx(void *) __ksym;

void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym;

extern int bpf_get_file_xattr(struct file *file, const char *name,
struct bpf_dynptr *value_ptr) __ksym;
extern int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr *digest_ptr) __ksym;
#endif
1 change: 1 addition & 0 deletions tools/testing/selftests/bpf/config
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ CONFIG_FPROBE=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_FUNCTION_ERROR_INJECTION=y
CONFIG_FUNCTION_TRACER=y
CONFIG_FS_VERITY=y
CONFIG_GENEVE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
Expand Down
134 changes: 134 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
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();
}
48 changes: 48 additions & 0 deletions tools/testing/selftests/bpf/progs/test_fsverity.c
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;
}
37 changes: 37 additions & 0 deletions tools/testing/selftests/bpf/progs/test_get_xattr.c
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;
}

0 comments on commit 341f06f

Please sign in to comment.