Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

security: Propagate caller information in bpf hooks

Certain bpf syscall subcommands are available for usage from both
userspace and the kernel. LSM modules or eBPF gatekeeper programs may
need to take a different course of action depending on whether or not
a BPF syscall originated from the kernel or userspace.

Additionally, some of the bpf_attr struct fields contain pointers to
arbitrary memory. Currently the functionality to determine whether or
not a pointer refers to kernel memory or userspace memory is exposed
to the bpf verifier, but that information is missing from various LSM
hooks.

Here we augment the LSM hooks to provide this data, by simply passing
a boolean flag indicating whether or not the call originated in the
kernel, in any hook that contains a bpf_attr struct that corresponds
to a subcommand that may be called from the kernel.

Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
Acked-by: Song Liu <song@kernel.org>
Acked-by: Paul Moore <paul@paul-moore.com>
Link: https://lore.kernel.org/r/20250310221737.821889-2-bboscaccy@linux.microsoft.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Blaise Boscaccy and committed by
Alexei Starovoitov
082f1db0 a03d3753

+37 -33
+3 -3
include/linux/lsm_hook_defs.h
··· 426 426 #endif /* CONFIG_AUDIT */ 427 427 428 428 #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) 430 430 LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode) 431 431 LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog) 432 432 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) 434 434 LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map) 435 435 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) 437 437 LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog) 438 438 LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr, 439 439 const struct path *path)
+6 -6
include/linux/security.h
··· 2249 2249 struct bpf_prog; 2250 2250 struct bpf_token; 2251 2251 #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); 2253 2253 extern int security_bpf_map(struct bpf_map *map, fmode_t fmode); 2254 2254 extern int security_bpf_prog(struct bpf_prog *prog); 2255 2255 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); 2257 2257 extern void security_bpf_map_free(struct bpf_map *map); 2258 2258 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); 2260 2260 extern void security_bpf_prog_free(struct bpf_prog *prog); 2261 2261 extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, 2262 2262 const struct path *path); ··· 2265 2265 extern int security_bpf_token_capable(const struct bpf_token *token, int cap); 2266 2266 #else 2267 2267 static inline int security_bpf(int cmd, union bpf_attr *attr, 2268 - unsigned int size) 2268 + unsigned int size, bool kernel) 2269 2269 { 2270 2270 return 0; 2271 2271 } ··· 2281 2281 } 2282 2282 2283 2283 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) 2285 2285 { 2286 2286 return 0; 2287 2287 } ··· 2290 2290 { } 2291 2291 2292 2292 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) 2294 2294 { 2295 2295 return 0; 2296 2296 }
+5 -5
kernel/bpf/syscall.c
··· 1315 1315 1316 1316 #define BPF_MAP_CREATE_LAST_FIELD map_token_fd 1317 1317 /* called via syscall */ 1318 - static int map_create(union bpf_attr *attr) 1318 + static int map_create(union bpf_attr *attr, bool kernel) 1319 1319 { 1320 1320 const struct bpf_map_ops *ops; 1321 1321 struct bpf_token *token = NULL; ··· 1505 1505 attr->btf_vmlinux_value_type_id; 1506 1506 } 1507 1507 1508 - err = security_bpf_map_create(map, attr, token); 1508 + err = security_bpf_map_create(map, attr, token, kernel); 1509 1509 if (err) 1510 1510 goto free_map_sec; 1511 1511 ··· 2942 2942 if (err < 0) 2943 2943 goto free_prog; 2944 2944 2945 - err = security_bpf_prog_load(prog, attr, token); 2945 + err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel); 2946 2946 if (err) 2947 2947 goto free_prog_sec; 2948 2948 ··· 5767 5767 if (copy_from_bpfptr(&attr, uattr, size) != 0) 5768 5768 return -EFAULT; 5769 5769 5770 - err = security_bpf(cmd, &attr, size); 5770 + err = security_bpf(cmd, &attr, size, uattr.is_kernel); 5771 5771 if (err < 0) 5772 5772 return err; 5773 5773 5774 5774 switch (cmd) { 5775 5775 case BPF_MAP_CREATE: 5776 - err = map_create(&attr); 5776 + err = map_create(&attr, uattr.is_kernel); 5777 5777 break; 5778 5778 case BPF_MAP_LOOKUP_ELEM: 5779 5779 err = map_lookup_elem(&attr);
+9 -6
security/security.c
··· 5627 5627 * @cmd: command 5628 5628 * @attr: bpf attribute 5629 5629 * @size: size 5630 + * @kernel: whether or not call originated from kernel 5630 5631 * 5631 5632 * Do a initial check for all bpf syscalls after the attribute is copied into 5632 5633 * the kernel. The actual security module can implement their own rules to ··· 5635 5634 * 5636 5635 * Return: Returns 0 if permission is granted. 5637 5636 */ 5638 - int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) 5637 + int security_bpf(int cmd, union bpf_attr *attr, unsigned int size, bool kernel) 5639 5638 { 5640 - return call_int_hook(bpf, cmd, attr, size); 5639 + return call_int_hook(bpf, cmd, attr, size, kernel); 5641 5640 } 5642 5641 5643 5642 /** ··· 5674 5673 * @map: BPF map object 5675 5674 * @attr: BPF syscall attributes used to create BPF map 5676 5675 * @token: BPF token used to grant user access 5676 + * @kernel: whether or not call originated from kernel 5677 5677 * 5678 5678 * Do a check when the kernel creates a new BPF map. This is also the 5679 5679 * point where LSM blob is allocated for LSMs that need them. ··· 5682 5680 * Return: Returns 0 on success, error on failure. 5683 5681 */ 5684 5682 int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, 5685 - struct bpf_token *token) 5683 + struct bpf_token *token, bool kernel) 5686 5684 { 5687 - return call_int_hook(bpf_map_create, map, attr, token); 5685 + return call_int_hook(bpf_map_create, map, attr, token, kernel); 5688 5686 } 5689 5687 5690 5688 /** ··· 5692 5690 * @prog: BPF program object 5693 5691 * @attr: BPF syscall attributes used to create BPF program 5694 5692 * @token: BPF token used to grant user access to BPF subsystem 5693 + * @kernel: whether or not call originated from kernel 5695 5694 * 5696 5695 * Perform an access control check when the kernel loads a BPF program and 5697 5696 * allocates associated BPF program object. This hook is also responsible for ··· 5701 5698 * Return: Returns 0 on success, error on failure. 5702 5699 */ 5703 5700 int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, 5704 - struct bpf_token *token) 5701 + struct bpf_token *token, bool kernel) 5705 5702 { 5706 - return call_int_hook(bpf_prog_load, prog, attr, token); 5703 + return call_int_hook(bpf_prog_load, prog, attr, token, kernel); 5707 5704 } 5708 5705 5709 5706 /**
+3 -3
security/selinux/hooks.c
··· 6866 6866 6867 6867 #ifdef CONFIG_BPF_SYSCALL 6868 6868 static int selinux_bpf(int cmd, union bpf_attr *attr, 6869 - unsigned int size) 6869 + unsigned int size, bool kernel) 6870 6870 { 6871 6871 u32 sid = current_sid(); 6872 6872 int ret; ··· 6953 6953 } 6954 6954 6955 6955 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) 6957 6957 { 6958 6958 struct bpf_security_struct *bpfsec; 6959 6959 ··· 6976 6976 } 6977 6977 6978 6978 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) 6980 6980 { 6981 6981 struct bpf_security_struct *bpfsec; 6982 6982
+2 -1
tools/testing/selftests/bpf/progs/rcu_read_lock.c
··· 242 242 } 243 243 244 244 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) 246 247 { 247 248 struct bpf_key *bkey; 248 249
+2 -2
tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c
··· 51 51 } 52 52 53 53 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) 55 55 { 56 56 return bpf_link_create_verify(cmd); 57 57 } 58 58 59 59 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) 61 61 { 62 62 return bpf_link_create_verify(cmd); 63 63 }
+3 -3
tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
··· 36 36 37 37 SEC("?lsm.s/bpf") 38 38 __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) 40 40 { 41 41 unsigned long val; 42 42 ··· 46 46 47 47 SEC("?lsm.s/bpf") 48 48 __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) 50 50 { 51 51 unsigned long val = 0; 52 52 ··· 55 55 } 56 56 57 57 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) 59 59 { 60 60 struct bpf_key *trusted_keyring; 61 61 struct bpf_dynptr ptr;
+1 -1
tools/testing/selftests/bpf/progs/test_lookup_key.c
··· 23 23 extern void bpf_key_put(struct bpf_key *key) __ksym; 24 24 25 25 SEC("lsm.s/bpf") 26 - int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size) 26 + int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size, bool kernel) 27 27 { 28 28 struct bpf_key *bkey; 29 29 __u32 pid;
+1 -1
tools/testing/selftests/bpf/progs/test_ptr_untrusted.c
··· 7 7 char tp_name[128]; 8 8 9 9 SEC("lsm.s/bpf") 10 - int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size) 10 + int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size, bool kernel) 11 11 { 12 12 switch (cmd) { 13 13 case BPF_RAW_TRACEPOINT_OPEN:
+1 -1
tools/testing/selftests/bpf/progs/test_task_under_cgroup.c
··· 49 49 } 50 50 51 51 SEC("lsm.s/bpf") 52 - int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size) 52 + int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size, bool kernel) 53 53 { 54 54 struct cgroup *cgrp = NULL; 55 55 struct task_struct *task;
+1 -1
tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c
··· 37 37 char _license[] SEC("license") = "GPL"; 38 38 39 39 SEC("lsm.s/bpf") 40 - int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size) 40 + int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size, bool kernel) 41 41 { 42 42 struct bpf_dynptr data_ptr, sig_ptr; 43 43 struct data *data_val;