> From: Daniel Borkmann [mailto:daniel@xxxxxxxxxxxxx] > Sent: Wednesday, August 10, 2022 12:53 AM > On 8/9/22 3:45 PM, Roberto Sassu wrote: > > Add the bpf_lookup_user_key(), bpf_lookup_system_key() and bpf_key_put() > > kfuncs, to respectively search a key with a given serial and flags, obtain > > a key from a pre-determined ID defined in include/linux/verification.h, and > > cleanup. > > > > Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx> > > --- > > include/linux/bpf.h | 6 ++ > > kernel/trace/bpf_trace.c | 151 > +++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 157 insertions(+) > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > index 0d56c23cc504..564b9e0b8c16 100644 > > --- a/include/linux/bpf.h > > +++ b/include/linux/bpf.h > > @@ -2572,4 +2572,10 @@ 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 */ > > > > +#ifdef CONFIG_KEYS > > +struct bpf_key { > > + struct key *key; > > + bool valid_ptr; > > +}; > > +#endif /* CONFIG_KEYS */ > > #endif /* _LINUX_BPF_H */ > > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > > index 68e5cdd24cef..33ca4cfe6e26 100644 > > --- a/kernel/trace/bpf_trace.c > > +++ b/kernel/trace/bpf_trace.c > > @@ -20,6 +20,7 @@ > > #include <linux/fprobe.h> > > #include <linux/bsearch.h> > > #include <linux/sort.h> > > +#include <linux/key.h> > > > > #include <net/bpf_sk_storage.h> > > > > @@ -1181,6 +1182,156 @@ 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 serial > > + * @flags: lookup-specific flags > > + * > > + * Search a key with a given *serial* and the provided *flags*. The > > + * returned key, if found, has the reference count incremented by > > + * one, and is stored in a bpf_key structure, returned to the caller. > > + * 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 1, to attempt creating a requested special > > + * keyring (e.g. session keyring), if it doesn't yet exist. Set > > + * *flags* with 2 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. > > + */ > > +noinline __weak struct bpf_key *bpf_lookup_user_key(u32 serial, u64 flags) > > Why the need for noinline and the __weak here and below? (If indeed needed > this > should probably be explained in the commit desc.) Oh, I took from v3 of KP's patch set. It is gone in v5. Will do the same as well. > > +{ > > + key_ref_t key_ref; > > + struct bpf_key *bkey; > > + > > + /* Keep in sync with include/linux/key.h. */ > > + if (flags > (KEY_LOOKUP_PARTIAL << 1) - 1) > > Can't we just simplify and test flags & > ~(KEY_LOOKUP_CREATE|KEY_LOOKUP_PARTIAL)? I thought as if we have many flags. > > + return NULL; > > + > > + /* Permission check is deferred until actual kfunc using the key. */ > > + 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 bkey; > > nit: just return NULL probably cleaner Ok. > > + } > > + > > + bkey->key = key_ref_to_ptr(key_ref); > > + bkey->valid_ptr = true; > > nit: I'd probably rename s/valid_ptr/has_ref/. Ok. > > + 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); 1 for both > > + * the primary and secondary keyring (where keys can be added only if they > > + * are vouched for by existing keys in those keyrings); 2 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 > > + */ > > +noinline __weak struct bpf_key *bpf_lookup_system_key(u64 id) > > +{ > > + struct bpf_key *bkey; > > + > > + /* Keep in sync with defs in include/linux/verification.h. */ > > + if (id > (unsigned long)VERIFY_USE_PLATFORM_KEYRING) > > + return NULL; > > + > > + bkey = kmalloc(sizeof(*bkey), GFP_KERNEL); > > nit: Can't this be GFP_ATOMIC? Then bpf_lookup_system_key doesn't need > KF_SLEEPABLE > attribute, fwiw. Overall, the bpf_lookup_{system,user}_key() look reasonable. Ok, will do. Thanks Roberto > > + if (!bkey) > > + return bkey; > > + > > + bkey->key = (struct key *)(unsigned long)id; > > + bkey->valid_ptr = 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*. > > + */ > > +noinline __weak void bpf_key_put(struct bpf_key *bkey) > > +{ > > + if (bkey->valid_ptr) > > + key_put(bkey->key); > > + > > + kfree(bkey); > > +} > > + > > +__diag_pop(); > > + > > +BTF_SET8_START(key_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 | KF_SLEEPABLE) > > +BTF_ID_FLAGS(func, bpf_key_put, KF_RELEASE) > > +BTF_SET8_END(key_kfunc_set) > > + > > +static const struct btf_kfunc_id_set bpf_key_kfunc_set = { > > + .owner = THIS_MODULE, > > + .set = &key_kfunc_set, > > +}; > > +#endif /* CONFIG_KEYS */ > > + > > +const struct btf_kfunc_id_set *kfunc_sets[] = { > > +#ifdef CONFIG_KEYS > > + &bpf_key_kfunc_set, > > +#endif /* CONFIG_KEYS */ > > +};