如果文件名以“t”开头,我想拒绝在 Linux 计算机上删除文件。
这是我所做的:
#define __TARGET_ARCH_arm64
#include <linux/ptrace.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
char LICENSE[] SEC("license") = "Dual BSD/GPL";
typedef struct {
int counter;
} atomic_t;
struct filename {
const char *name;
const char *uptr;
atomic_t refcnt;
struct audit_names *aname;
const char iname[0];
};
SEC("kprobe/do_unlinkat")
int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name)
{
char filename[128];
const char *ptr_filename = BPF_CORE_READ(name, name);
int ret = bpf_probe_read_kernel_str(filename, sizeof(filename), ptr_filename);
if (filename[0]=='t')
{
bpf_printk("This file starts by 't'");
// return 1; <- returning 1 or -1 does not "cancel" the syscall...
// I have also tried to change filename on the fly...
filename[0]='w';
bpf_copy_from_user((void *) ptr_filename, 1, filename);
// bpf_copy_from_user((void *) name->name, 1, filename); // Also tried this...
}
bpf_printk("Deleting this file:%s", filename);
return 0;
}
我首先不明白的是 BPF_KPROBE 的返回值是什么? 我原以为返回 0 以外的值会取消系统调用。 但我的文件还是被删除了...
我尝试过更改文件名。但是当我尝试编译 eBPF 时 bpf_copy_from_user 会导致错误:
libbpf: prog 'do_unlinkat': BPF program load failed: Permission denied
libbpf: prog 'do_unlinkat': -- BEGIN PROG LOAD LOG -- arg#0 reference
type('FWD pt_regs') size cannot be determined: -22 0: R1=ctx() R10=fp0
有什么想法吗?
我首先不明白的是 BPF_KPROBE 的返回值是什么? 我原以为返回 0 以外的值会取消系统调用。但我的文件还是被删除了...
kprobe的返回值是没有意义的,没有任何作用。 kprobe 是一个观察工具,而不是实现功能,因此这样的设计。
bpf_override_return
,它是一个帮助器,可以设置返回值并提前退出被探测的函数。它确实需要使用 CONFIG_BPF_KPROBE_OVERRIDE=y
kconfig 编译内核。这是一种已知有效的技术,https://tetragon.io/也使用它来实现运行时安全强制。
如果以上方法因任何原因不能满足您的需求,您可以考虑LSM 计划。 LSM 程序允许您将 eBPF 代码挂钩到 SELinux/AppArmor 也使用的 LSM 挂钩中。这些是为了强制执行,根据特定的钩子,您可以返回布尔值或错误代码。此功能至少需要内核版本 v5.7,并且您的内核需要使用
CONFIG_BPF_LSM=y
kconfig 进行编译。
path_unlink
钩子就是你想要的。它的描述:
@path_unlink: Check the permission to remove a hard link to a file. @dir contains the path structure of parent directory of the file. @dentry contains the dentry structure for file to be unlinked. Return 0 if permission is granted.
它被控制在
CONFIG_SECURITY_PATH
kconfig 后面。如果你的内核没有它,它们 inode_unlink
是一个类似的钩子,但不会直接给你路径,所以更多的工作。