Skip to content

Commit a9041fb

Browse files
author
Alexei Starovoitov
committed
Merge branch 'security-propagate-caller-information-in-bpf-hooks'
Blaise Boscaccy says: ==================== While trying to implement an eBPF gatekeeper program, we ran into an issue whereas the LSM hooks are missing some relevant data. Certain subcommands passed to the bpf() syscall can be invoked from either the kernel or userspace. Additionally, some fields in the bpf_attr struct contain pointers, and depending on where the subcommand was invoked, they could point to either user or kernel memory. One example of this is the bpf_prog_load subcommand and its fd_array. This data is made available and used by the verifier but not made available to the LSM subsystem. This patchset simply exposes that information to applicable LSM hooks. Change list: - v6 -> v7 - use gettid/pid in lieu of getpid/tgid in test condition - v5 -> v6 - fix regression caused by is_kernel renaming - simplify test logic - v4 -> v5 - merge v4 selftest breakout patch back into a single patch - change "is_kernel" to "kernel" - add selftest using new kernel flag - v3 -> v4 - split out selftest changes into a separate patch - v2 -> v3 - reorder params so that the new boolean flag is the last param - fixup function signatures in bpf selftests - v1 -> v2 - Pass a boolean flag in lieu of bpfptr_t Revisions: - v6 https://lore.kernel.org/bpf/20250308013314.719150-1-bboscaccy@linux.microsoft.com/ - v5 https://lore.kernel.org/bpf/20250307213651.3065714-1-bboscaccy@linux.microsoft.com/ - v4 https://lore.kernel.org/bpf/20250304203123.3935371-1-bboscaccy@linux.microsoft.com/ - v3 https://lore.kernel.org/bpf/20250303222416.3909228-1-bboscaccy@linux.microsoft.com/ - v2 https://lore.kernel.org/bpf/20250228165322.3121535-1-bboscaccy@linux.microsoft.com/ - v1 https://lore.kernel.org/bpf/20250226003055.1654837-1-bboscaccy@linux.microsoft.com/ ==================== Link: https://patch.msgid.link/20250310221737.821889-1-bboscaccy@linux.microsoft.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2 parents a03d375 + 7987f16 commit a9041fb

File tree

14 files changed

+108
-33
lines changed

14 files changed

+108
-33
lines changed

include/linux/lsm_hook_defs.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,14 @@ LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
426426
#endif /* CONFIG_AUDIT */
427427

428428
#ifdef CONFIG_BPF_SYSCALL
429-
LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size)
429+
LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
430430
LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode)
431431
LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog)
432432
LSM_HOOK(int, 0, bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
433-
struct bpf_token *token)
433+
struct bpf_token *token, bool kernel)
434434
LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map)
435435
LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
436-
struct bpf_token *token)
436+
struct bpf_token *token, bool kernel)
437437
LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog)
438438
LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr,
439439
const struct path *path)

include/linux/security.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,14 +2249,14 @@ struct bpf_map;
22492249
struct bpf_prog;
22502250
struct bpf_token;
22512251
#ifdef CONFIG_SECURITY
2252-
extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
2252+
extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size, bool kernel);
22532253
extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
22542254
extern int security_bpf_prog(struct bpf_prog *prog);
22552255
extern int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
2256-
struct bpf_token *token);
2256+
struct bpf_token *token, bool kernel);
22572257
extern void security_bpf_map_free(struct bpf_map *map);
22582258
extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
2259-
struct bpf_token *token);
2259+
struct bpf_token *token, bool kernel);
22602260
extern void security_bpf_prog_free(struct bpf_prog *prog);
22612261
extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
22622262
const struct path *path);
@@ -2265,7 +2265,7 @@ extern int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cm
22652265
extern int security_bpf_token_capable(const struct bpf_token *token, int cap);
22662266
#else
22672267
static inline int security_bpf(int cmd, union bpf_attr *attr,
2268-
unsigned int size)
2268+
unsigned int size, bool kernel)
22692269
{
22702270
return 0;
22712271
}
@@ -2281,7 +2281,7 @@ static inline int security_bpf_prog(struct bpf_prog *prog)
22812281
}
22822282

22832283
static inline int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
2284-
struct bpf_token *token)
2284+
struct bpf_token *token, bool kernel)
22852285
{
22862286
return 0;
22872287
}
@@ -2290,7 +2290,7 @@ static inline void security_bpf_map_free(struct bpf_map *map)
22902290
{ }
22912291

22922292
static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
2293-
struct bpf_token *token)
2293+
struct bpf_token *token, bool kernel)
22942294
{
22952295
return 0;
22962296
}

kernel/bpf/syscall.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,7 +1315,7 @@ static bool bpf_net_capable(void)
13151315

13161316
#define BPF_MAP_CREATE_LAST_FIELD map_token_fd
13171317
/* called via syscall */
1318-
static int map_create(union bpf_attr *attr)
1318+
static int map_create(union bpf_attr *attr, bool kernel)
13191319
{
13201320
const struct bpf_map_ops *ops;
13211321
struct bpf_token *token = NULL;
@@ -1505,7 +1505,7 @@ static int map_create(union bpf_attr *attr)
15051505
attr->btf_vmlinux_value_type_id;
15061506
}
15071507

1508-
err = security_bpf_map_create(map, attr, token);
1508+
err = security_bpf_map_create(map, attr, token, kernel);
15091509
if (err)
15101510
goto free_map_sec;
15111511

@@ -2942,7 +2942,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
29422942
if (err < 0)
29432943
goto free_prog;
29442944

2945-
err = security_bpf_prog_load(prog, attr, token);
2945+
err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel);
29462946
if (err)
29472947
goto free_prog_sec;
29482948

@@ -5767,13 +5767,13 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size)
57675767
if (copy_from_bpfptr(&attr, uattr, size) != 0)
57685768
return -EFAULT;
57695769

5770-
err = security_bpf(cmd, &attr, size);
5770+
err = security_bpf(cmd, &attr, size, uattr.is_kernel);
57715771
if (err < 0)
57725772
return err;
57735773

57745774
switch (cmd) {
57755775
case BPF_MAP_CREATE:
5776-
err = map_create(&attr);
5776+
err = map_create(&attr, uattr.is_kernel);
57775777
break;
57785778
case BPF_MAP_LOOKUP_ELEM:
57795779
err = map_lookup_elem(&attr);

security/security.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5627,16 +5627,17 @@ int security_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
56275627
* @cmd: command
56285628
* @attr: bpf attribute
56295629
* @size: size
5630+
* @kernel: whether or not call originated from kernel
56305631
*
56315632
* Do a initial check for all bpf syscalls after the attribute is copied into
56325633
* the kernel. The actual security module can implement their own rules to
56335634
* check the specific cmd they need.
56345635
*
56355636
* Return: Returns 0 if permission is granted.
56365637
*/
5637-
int security_bpf(int cmd, union bpf_attr *attr, unsigned int size)
5638+
int security_bpf(int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
56385639
{
5639-
return call_int_hook(bpf, cmd, attr, size);
5640+
return call_int_hook(bpf, cmd, attr, size, kernel);
56405641
}
56415642

56425643
/**
@@ -5673,23 +5674,25 @@ int security_bpf_prog(struct bpf_prog *prog)
56735674
* @map: BPF map object
56745675
* @attr: BPF syscall attributes used to create BPF map
56755676
* @token: BPF token used to grant user access
5677+
* @kernel: whether or not call originated from kernel
56765678
*
56775679
* Do a check when the kernel creates a new BPF map. This is also the
56785680
* point where LSM blob is allocated for LSMs that need them.
56795681
*
56805682
* Return: Returns 0 on success, error on failure.
56815683
*/
56825684
int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
5683-
struct bpf_token *token)
5685+
struct bpf_token *token, bool kernel)
56845686
{
5685-
return call_int_hook(bpf_map_create, map, attr, token);
5687+
return call_int_hook(bpf_map_create, map, attr, token, kernel);
56865688
}
56875689

56885690
/**
56895691
* security_bpf_prog_load() - Check if loading of BPF program is allowed
56905692
* @prog: BPF program object
56915693
* @attr: BPF syscall attributes used to create BPF program
56925694
* @token: BPF token used to grant user access to BPF subsystem
5695+
* @kernel: whether or not call originated from kernel
56935696
*
56945697
* Perform an access control check when the kernel loads a BPF program and
56955698
* allocates associated BPF program object. This hook is also responsible for
@@ -5698,9 +5701,9 @@ int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
56985701
* Return: Returns 0 on success, error on failure.
56995702
*/
57005703
int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
5701-
struct bpf_token *token)
5704+
struct bpf_token *token, bool kernel)
57025705
{
5703-
return call_int_hook(bpf_prog_load, prog, attr, token);
5706+
return call_int_hook(bpf_prog_load, prog, attr, token, kernel);
57045707
}
57055708

57065709
/**

security/selinux/hooks.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6866,7 +6866,7 @@ static int selinux_ib_alloc_security(void *ib_sec)
68666866

68676867
#ifdef CONFIG_BPF_SYSCALL
68686868
static int selinux_bpf(int cmd, union bpf_attr *attr,
6869-
unsigned int size)
6869+
unsigned int size, bool kernel)
68706870
{
68716871
u32 sid = current_sid();
68726872
int ret;
@@ -6953,7 +6953,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
69536953
}
69546954

69556955
static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
6956-
struct bpf_token *token)
6956+
struct bpf_token *token, bool kernel)
69576957
{
69586958
struct bpf_security_struct *bpfsec;
69596959

@@ -6976,7 +6976,7 @@ static void selinux_bpf_map_free(struct bpf_map *map)
69766976
}
69776977

69786978
static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
6979-
struct bpf_token *token)
6979+
struct bpf_token *token, bool kernel)
69806980
{
69816981
struct bpf_security_struct *bpfsec;
69826982

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Microsoft */
3+
#include <test_progs.h>
4+
#include "kfunc_call_test.skel.h"
5+
#include "kfunc_call_test.lskel.h"
6+
#include "test_kernel_flag.skel.h"
7+
8+
void test_kernel_flag(void)
9+
{
10+
struct test_kernel_flag *lsm_skel;
11+
struct kfunc_call_test *skel = NULL;
12+
struct kfunc_call_test_lskel *lskel = NULL;
13+
int ret;
14+
15+
lsm_skel = test_kernel_flag__open_and_load();
16+
if (!ASSERT_OK_PTR(lsm_skel, "lsm_skel"))
17+
return;
18+
19+
lsm_skel->bss->monitored_tid = gettid();
20+
21+
ret = test_kernel_flag__attach(lsm_skel);
22+
if (!ASSERT_OK(ret, "test_kernel_flag__attach"))
23+
goto close_prog;
24+
25+
/* Test with skel. This should pass the gatekeeper */
26+
skel = kfunc_call_test__open_and_load();
27+
if (!ASSERT_OK_PTR(skel, "skel"))
28+
goto close_prog;
29+
30+
/* Test with lskel. This should fail due to blocking kernel-based bpf() invocations */
31+
lskel = kfunc_call_test_lskel__open_and_load();
32+
if (!ASSERT_ERR_PTR(lskel, "lskel"))
33+
goto close_prog;
34+
35+
close_prog:
36+
if (skel)
37+
kfunc_call_test__destroy(skel);
38+
if (lskel)
39+
kfunc_call_test_lskel__destroy(lskel);
40+
41+
lsm_skel->bss->monitored_tid = 0;
42+
test_kernel_flag__destroy(lsm_skel);
43+
}

tools/testing/selftests/bpf/progs/rcu_read_lock.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ int inproper_sleepable_helper(void *ctx)
242242
}
243243

244244
SEC("?lsm.s/bpf")
245-
int BPF_PROG(inproper_sleepable_kfunc, int cmd, union bpf_attr *attr, unsigned int size)
245+
int BPF_PROG(inproper_sleepable_kfunc, int cmd, union bpf_attr *attr, unsigned int size,
246+
bool kernel)
246247
{
247248
struct bpf_key *bkey;
248249

tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ static int bpf_link_create_verify(int cmd)
5151
}
5252

5353
SEC("lsm/bpf")
54-
int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size)
54+
int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
5555
{
5656
return bpf_link_create_verify(cmd);
5757
}
5858

5959
SEC("lsm.s/bpf")
60-
int BPF_PROG(lsm_s_run, int cmd, union bpf_attr *attr, unsigned int size)
60+
int BPF_PROG(lsm_s_run, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
6161
{
6262
return bpf_link_create_verify(cmd);
6363
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
/*
4+
* Copyright (C) 2025 Microsoft Corporation
5+
*
6+
* Author: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
7+
*/
8+
9+
#include "vmlinux.h"
10+
#include <errno.h>
11+
#include <bpf/bpf_helpers.h>
12+
#include <bpf/bpf_tracing.h>
13+
14+
char _license[] SEC("license") = "GPL";
15+
16+
__u32 monitored_tid;
17+
18+
SEC("lsm.s/bpf")
19+
int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
20+
{
21+
__u32 tid;
22+
23+
tid = bpf_get_current_pid_tgid() & 0xFFFFFFFF;
24+
if (!kernel || tid != monitored_tid)
25+
return 0;
26+
else
27+
return -EINVAL;
28+
}

tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ char _license[] SEC("license") = "GPL";
3636

3737
SEC("?lsm.s/bpf")
3838
__failure __msg("cannot pass in dynptr at an offset=-8")
39-
int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size)
39+
int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
4040
{
4141
unsigned long val;
4242

@@ -46,7 +46,7 @@ int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size)
4646

4747
SEC("?lsm.s/bpf")
4848
__failure __msg("arg#0 expected pointer to stack or const struct bpf_dynptr")
49-
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size)
49+
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
5050
{
5151
unsigned long val = 0;
5252

@@ -55,7 +55,7 @@ int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size)
5555
}
5656

5757
SEC("lsm.s/bpf")
58-
int BPF_PROG(dynptr_data_null, int cmd, union bpf_attr *attr, unsigned int size)
58+
int BPF_PROG(dynptr_data_null, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
5959
{
6060
struct bpf_key *trusted_keyring;
6161
struct bpf_dynptr ptr;

0 commit comments

Comments
 (0)