Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kernel/trace/bpf_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ static const struct bpf_func_proto bpf_d_path_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_d_path_btf_ids[0],
.arg2_type = ARG_PTR_TO_MEM,
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
.arg3_type = ARG_CONST_SIZE_OR_ZERO,
.allowed = bpf_d_path_allowed,
};
Expand Down
64 changes: 64 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/d_path.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,67 @@ static void test_d_path_check_types(void)
test_d_path_check_types__destroy(skel);
}

static void test_d_path_lsm(void)
{
struct test_d_path *skel;
int err;
int pipefd[2];
pid_t pid;

skel = test_d_path__open_and_load();
if (!ASSERT_OK_PTR(skel, "d_path skeleton failed"))
return;

err = test_d_path__attach(skel);
if (!ASSERT_OK(err, "attach failed"))
goto cleanup;

/* Prepare the test binary */
system("cp /bin/true /tmp/bpf_d_path_test 2>/dev/null || :");

if (!ASSERT_OK(pipe(pipefd), "pipe failed"))
goto cleanup;

pid = fork();
if (!ASSERT_GE(pid, 0, "fork failed")) {
close(pipefd[0]);
close(pipefd[1]);
goto cleanup;
}

if (pid == 0) {
/* Child */
char buf;

close(pipefd[1]);
/* Wait for parent to set PID in BPF map */
if (read(pipefd[0], &buf, 1) != 1)
exit(1);
close(pipefd[0]);
execl("/tmp/bpf_d_path_test", "/tmp/bpf_d_path_test", NULL);
exit(1);
}

/* Parent */
close(pipefd[0]);

/* Update BPF map with child PID */
skel->bss->my_pid = pid;

/* Signal child to proceed */
write(pipefd[1], "G", 1);
close(pipefd[1]);

/* Wait for child */
waitpid(pid, NULL, 0);

ASSERT_EQ(skel->bss->called_lsm, 1, "lsm hook called");
ASSERT_EQ(skel->bss->lsm_match, 1, "lsm match");

cleanup:
test_d_path__destroy(skel);
}

void test_d_path(void)
{
if (test__start_subtest("basic"))
Expand All @@ -205,4 +266,7 @@ void test_d_path(void)

if (test__start_subtest("check_alloc_mem"))
test_d_path_check_types();

if (test__start_subtest("lsm"))
test_d_path_lsm();
}
33 changes: 33 additions & 0 deletions tools/testing/selftests/bpf/progs/test_d_path.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ int rets_close[MAX_FILES] = {};

int called_stat = 0;
int called_close = 0;
int called_lsm = 0;
int lsm_match = 0;

SEC("fentry/security_inode_getattr")
int BPF_PROG(prog_stat, struct path *path, struct kstat *stat,
Expand Down Expand Up @@ -62,4 +64,35 @@ int BPF_PROG(prog_close, struct file *file, void *id)
return 0;
}

SEC("lsm/bprm_check_security")
int BPF_PROG(prog_lsm, struct linux_binprm *bprm)
{
pid_t pid = bpf_get_current_pid_tgid() >> 32;
char path[MAX_PATH_LEN] = {};
int ret;

if (pid != my_pid)
return 0;

called_lsm = 1;
ret = bpf_d_path(&bprm->file->f_path, path, MAX_PATH_LEN);
if (ret < 0)
return 0;

{
static const char target_dir[] = "/tmp/";

#pragma unroll
for (int i = 0; i < sizeof(target_dir) - 1; i++) {
if (path[i] != target_dir[i]) {
lsm_match = -1; /* mismatch */
return 0;
}
}
}

lsm_match = 1; /* prefix match */
return 0;
}

char _license[] SEC("license") = "GPL";
Loading