forked from mirrors/linux
		
	bpf: Add bpf_lookup_*_key() and bpf_key_put() kfuncs
Add the bpf_lookup_user_key(), bpf_lookup_system_key() and bpf_key_put() kfuncs, to respectively search a key with a given key handle serial number and flags, obtain a key from a pre-determined ID defined in include/linux/verification.h, and cleanup. Introduce system_keyring_id_check() to validate the keyring ID parameter of bpf_lookup_system_key(). Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Acked-by: Song Liu <song@kernel.org> Link: https://lore.kernel.org/r/20220920075951.929132-8-roberto.sassu@huaweicloud.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									90fd8f26ed
								
							
						
					
					
						commit
						f3cf4134c5
					
				
					 3 changed files with 151 additions and 0 deletions
				
			
		|  | @ -2664,4 +2664,12 @@ static inline void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype) {} | |||
| static inline void bpf_cgroup_atype_put(int cgroup_atype) {} | ||||
| #endif /* CONFIG_BPF_LSM */ | ||||
| 
 | ||||
| struct key; | ||||
| 
 | ||||
| #ifdef CONFIG_KEYS | ||||
| struct bpf_key { | ||||
| 	struct key *key; | ||||
| 	bool has_ref; | ||||
| }; | ||||
| #endif /* CONFIG_KEYS */ | ||||
| #endif /* _LINUX_BPF_H */ | ||||
|  |  | |||
|  | @ -17,6 +17,14 @@ | |||
| #define VERIFY_USE_SECONDARY_KEYRING ((struct key *)1UL) | ||||
| #define VERIFY_USE_PLATFORM_KEYRING  ((struct key *)2UL) | ||||
| 
 | ||||
| static inline int system_keyring_id_check(u64 id) | ||||
| { | ||||
| 	if (id > (unsigned long)VERIFY_USE_PLATFORM_KEYRING) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The use to which an asymmetric key is being put. | ||||
|  */ | ||||
|  |  | |||
|  | @ -20,6 +20,8 @@ | |||
| #include <linux/fprobe.h> | ||||
| #include <linux/bsearch.h> | ||||
| #include <linux/sort.h> | ||||
| #include <linux/key.h> | ||||
| #include <linux/verification.h> | ||||
| 
 | ||||
| #include <net/bpf_sk_storage.h> | ||||
| 
 | ||||
|  | @ -1181,6 +1183,139 @@ static const struct bpf_func_proto bpf_get_func_arg_cnt_proto = { | |||
| 	.arg1_type	= ARG_PTR_TO_CTX, | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_KEYS | ||||
| __diag_push(); | ||||
| __diag_ignore_all("-Wmissing-prototypes", | ||||
| 		  "kfuncs which will be used in BPF programs"); | ||||
| 
 | ||||
| /**
 | ||||
|  * bpf_lookup_user_key - lookup a key by its serial | ||||
|  * @serial: key handle serial number | ||||
|  * @flags: lookup-specific flags | ||||
|  * | ||||
|  * Search a key with a given *serial* and the provided *flags*. | ||||
|  * If found, increment the reference count of the key by one, and | ||||
|  * return it in the bpf_key structure. | ||||
|  * | ||||
|  * The bpf_key structure must be passed to bpf_key_put() when done | ||||
|  * with it, so that the key reference count is decremented and the | ||||
|  * bpf_key structure is freed. | ||||
|  * | ||||
|  * Permission checks are deferred to the time the key is used by | ||||
|  * one of the available key-specific kfuncs. | ||||
|  * | ||||
|  * Set *flags* with KEY_LOOKUP_CREATE, to attempt creating a requested | ||||
|  * special keyring (e.g. session keyring), if it doesn't yet exist. | ||||
|  * Set *flags* with KEY_LOOKUP_PARTIAL, to lookup a key without waiting | ||||
|  * for the key construction, and to retrieve uninstantiated keys (keys | ||||
|  * without data attached to them). | ||||
|  * | ||||
|  * Return: a bpf_key pointer with a valid key pointer if the key is found, a | ||||
|  *         NULL pointer otherwise. | ||||
|  */ | ||||
| struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags) | ||||
| { | ||||
| 	key_ref_t key_ref; | ||||
| 	struct bpf_key *bkey; | ||||
| 
 | ||||
| 	if (flags & ~KEY_LOOKUP_ALL) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Permission check is deferred until the key is used, as the | ||||
| 	 * intent of the caller is unknown here. | ||||
| 	 */ | ||||
| 	key_ref = lookup_user_key(serial, flags, KEY_DEFER_PERM_CHECK); | ||||
| 	if (IS_ERR(key_ref)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	bkey = kmalloc(sizeof(*bkey), GFP_KERNEL); | ||||
| 	if (!bkey) { | ||||
| 		key_put(key_ref_to_ptr(key_ref)); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	bkey->key = key_ref_to_ptr(key_ref); | ||||
| 	bkey->has_ref = true; | ||||
| 
 | ||||
| 	return bkey; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * bpf_lookup_system_key - lookup a key by a system-defined ID | ||||
|  * @id: key ID | ||||
|  * | ||||
|  * Obtain a bpf_key structure with a key pointer set to the passed key ID. | ||||
|  * The key pointer is marked as invalid, to prevent bpf_key_put() from | ||||
|  * attempting to decrement the key reference count on that pointer. The key | ||||
|  * pointer set in such way is currently understood only by | ||||
|  * verify_pkcs7_signature(). | ||||
|  * | ||||
|  * Set *id* to one of the values defined in include/linux/verification.h: | ||||
|  * 0 for the primary keyring (immutable keyring of system keys); | ||||
|  * VERIFY_USE_SECONDARY_KEYRING for both the primary and secondary keyring | ||||
|  * (where keys can be added only if they are vouched for by existing keys | ||||
|  * in those keyrings); VERIFY_USE_PLATFORM_KEYRING for the platform | ||||
|  * keyring (primarily used by the integrity subsystem to verify a kexec'ed | ||||
|  * kerned image and, possibly, the initramfs signature). | ||||
|  * | ||||
|  * Return: a bpf_key pointer with an invalid key pointer set from the | ||||
|  *         pre-determined ID on success, a NULL pointer otherwise | ||||
|  */ | ||||
| struct bpf_key *bpf_lookup_system_key(u64 id) | ||||
| { | ||||
| 	struct bpf_key *bkey; | ||||
| 
 | ||||
| 	if (system_keyring_id_check(id) < 0) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	bkey = kmalloc(sizeof(*bkey), GFP_ATOMIC); | ||||
| 	if (!bkey) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	bkey->key = (struct key *)(unsigned long)id; | ||||
| 	bkey->has_ref = false; | ||||
| 
 | ||||
| 	return bkey; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * bpf_key_put - decrement key reference count if key is valid and free bpf_key | ||||
|  * @bkey: bpf_key structure | ||||
|  * | ||||
|  * Decrement the reference count of the key inside *bkey*, if the pointer | ||||
|  * is valid, and free *bkey*. | ||||
|  */ | ||||
| void bpf_key_put(struct bpf_key *bkey) | ||||
| { | ||||
| 	if (bkey->has_ref) | ||||
| 		key_put(bkey->key); | ||||
| 
 | ||||
| 	kfree(bkey); | ||||
| } | ||||
| 
 | ||||
| __diag_pop(); | ||||
| 
 | ||||
| BTF_SET8_START(key_sig_kfunc_set) | ||||
| BTF_ID_FLAGS(func, bpf_lookup_user_key, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) | ||||
| BTF_ID_FLAGS(func, bpf_lookup_system_key, KF_ACQUIRE | KF_RET_NULL) | ||||
| BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE) | ||||
| BTF_SET8_END(key_sig_kfunc_set) | ||||
| 
 | ||||
| static const struct btf_kfunc_id_set bpf_key_sig_kfunc_set = { | ||||
| 	.owner = THIS_MODULE, | ||||
| 	.set = &key_sig_kfunc_set, | ||||
| }; | ||||
| 
 | ||||
| static int __init bpf_key_sig_kfuncs_init(void) | ||||
| { | ||||
| 	return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, | ||||
| 					 &bpf_key_sig_kfunc_set); | ||||
| } | ||||
| 
 | ||||
| late_initcall(bpf_key_sig_kfuncs_init); | ||||
| #endif /* CONFIG_KEYS */ | ||||
| 
 | ||||
| static const struct bpf_func_proto * | ||||
| bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) | ||||
| { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Roberto Sassu
						Roberto Sassu