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) {} | static inline void bpf_cgroup_atype_put(int cgroup_atype) {} | ||||||
| #endif /* CONFIG_BPF_LSM */ | #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 */ | #endif /* _LINUX_BPF_H */ | ||||||
|  |  | ||||||
|  | @ -17,6 +17,14 @@ | ||||||
| #define VERIFY_USE_SECONDARY_KEYRING ((struct key *)1UL) | #define VERIFY_USE_SECONDARY_KEYRING ((struct key *)1UL) | ||||||
| #define VERIFY_USE_PLATFORM_KEYRING  ((struct key *)2UL) | #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. |  * The use to which an asymmetric key is being put. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -20,6 +20,8 @@ | ||||||
| #include <linux/fprobe.h> | #include <linux/fprobe.h> | ||||||
| #include <linux/bsearch.h> | #include <linux/bsearch.h> | ||||||
| #include <linux/sort.h> | #include <linux/sort.h> | ||||||
|  | #include <linux/key.h> | ||||||
|  | #include <linux/verification.h> | ||||||
| 
 | 
 | ||||||
| #include <net/bpf_sk_storage.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, | 	.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 * | static const struct bpf_func_proto * | ||||||
| bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) | 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