-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'bpf-file-verification-with-lsm-and-fsverity'
Song Liu says: ==================== bpf: File verification with LSM and fsverity Changes v14 => v15: 1. Fix selftest build without CONFIG_FS_VERITY. (Alexei) 2. Add Acked-by from KP. Changes v13 => v14: 1. Add "static" for bpf_fs_kfunc_set. 2. Add Acked-by from Christian Brauner. Changes v12 => v13: 1. Only keep 4/9 through 9/9 of v12, as the first 3 patches already applied; 2. Use new macro __bpf_kfunc_[start|end]_defs(). Changes v11 => v12: 1. Fix typo (data_ptr => sig_ptr) in bpf_get_file_xattr(). Changes v10 => v11: 1. Let __bpf_dynptr_data() return const void *. (Andrii) 2. Optimize code to reuse output from __bpf_dynptr_size(). (Andrii) 3. Add __diag_ignore_all("-Wmissing-declarations") for kfunc definition. 4. Fix an off indentation. (Andrii) Changes v9 => v10: 1. Remove WARN_ON_ONCE() from check_reg_const_str. (Alexei) Changes v8 => v9: 1. Fix test_progs kfunc_dynptr_param/dynptr_data_null. Changes v7 => v8: 1. Do not use bpf_dynptr_slice* in the kernel. Add __bpf_dynptr_data* and use them in ther kernel. (Andrii) Changes v6 => v7: 1. Change "__const_str" annotation to "__str". (Alexei, Andrii) 2. Add KF_TRUSTED_ARGS flag for both new kfuncs. (KP) 3. Only allow bpf_get_file_xattr() to read xattr with "user." prefix. 4. Add Acked-by from Eric Biggers. Changes v5 => v6: 1. Let fsverity_init_bpf() return void. (Eric Biggers) 2. Sort things in alphabetic orders. (Eric Biggers) Changes v4 => v5: 1. Revise commit logs. (Alexei) Changes v3 => v4: 1. Fix error reported by CI. 2. Update comments of bpf_dynptr_slice* that they may return error pointer. Changes v2 => v3: 1. Rebase and resolve conflicts. Changes v1 => v2: 1. Let bpf_get_file_xattr() use const string for arg "name". (Alexei) 2. Add recursion prevention with allowlist. (Alexei) 3. Let bpf_get_file_xattr() use __vfs_getxattr() to avoid recursion, as vfs_getxattr() calls into other LSM hooks. 4. Do not use dynptr->data directly, use helper insteadd. (Andrii) 5. Fixes with bpf_get_fsverity_digest. (Eric Biggers) 6. Add documentation. (Eric Biggers) 7. Fix some compile warnings. (kernel test robot) This set enables file verification with BPF LSM and fsverity. In this solution, fsverity is used to provide reliable and efficient hash of files; and BPF LSM is used to implement signature verification (against asymmetric keys), and to enforce access control. This solution can be used to implement access control in complicated cases. For example: only signed python binary and signed python script and access special files/devices/ports. Thanks, Song ==================== Link: https://lore.kernel.org/r/20231129234417.856536-1-song@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
- Loading branch information
Showing
15 changed files
with
688 additions
and
9 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
.. SPDX-License-Identifier: GPL-2.0 | ||
.. _fs_kfuncs-header-label: | ||
|
||
===================== | ||
BPF filesystem kfuncs | ||
===================== | ||
|
||
BPF LSM programs need to access filesystem data from LSM hooks. The following | ||
BPF kfuncs can be used to get these data. | ||
|
||
* ``bpf_get_file_xattr()`` | ||
|
||
* ``bpf_get_fsverity_digest()`` | ||
|
||
To avoid recursions, these kfuncs follow the following rules: | ||
|
||
1. These kfuncs are only permitted from BPF LSM function. | ||
2. These kfuncs should not call into other LSM hooks, i.e. security_*(). For | ||
example, ``bpf_get_file_xattr()`` does not use ``vfs_getxattr()``, because | ||
the latter calls LSM hook ``security_inode_getxattr``. |
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
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
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(); | ||
} |
Oops, something went wrong.