lkml.org 
[lkml]   [2022]   [Jun]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v4 2/4] bpf: Add bpf_request_key_by_id() helper
Date
Add the bpf_request_key_by_id() helper, so that an eBPF program can obtain
a suitable key pointer to pass to the bpf_verify_pkcs7_signature() helper,
to be introduced in a later patch.

The passed identifier can have the following values: 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); ULONG_MAX for the session keyring (for
testing purposes).

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
include/uapi/linux/bpf.h | 17 +++++++++++++++++
kernel/bpf/bpf_lsm.c | 30 ++++++++++++++++++++++++++++++
scripts/bpf_doc.py | 2 ++
tools/include/uapi/linux/bpf.h | 17 +++++++++++++++++
4 files changed, 66 insertions(+)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f4009dbdf62d..dfd93e0e0759 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -5249,6 +5249,22 @@ union bpf_attr {
* Pointer to the underlying dynptr data, NULL if the dynptr is
* read-only, if the dynptr is invalid, or if the offset and length
* is out of bounds.
+ *
+ * struct key *bpf_request_key_by_id(unsigned long id)
+ * Description
+ * Request a keyring by *id*.
+ *
+ * *id* can have the following values (some defined in
+ * 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); ULONG_MAX
+ * for the session keyring (for testing purposes).
+ * Return
+ * A non-NULL pointer if *id* is valid and not 0, a NULL pointer
+ * otherwise.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -5455,6 +5471,7 @@ union bpf_attr {
FN(dynptr_read), \
FN(dynptr_write), \
FN(dynptr_data), \
+ FN(request_key_by_id), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index c1351df9f7ee..e1911812398b 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -16,6 +16,7 @@
#include <linux/bpf_local_storage.h>
#include <linux/btf_ids.h>
#include <linux/ima.h>
+#include <linux/verification.h>

/* For every LSM hook that allows attachment of BPF programs, declare a nop
* function where a BPF program can be attached.
@@ -132,6 +133,31 @@ static const struct bpf_func_proto bpf_get_attach_cookie_proto = {
.arg1_type = ARG_PTR_TO_CTX,
};

+#ifdef CONFIG_KEYS
+BTF_ID_LIST_SINGLE(bpf_request_key_by_id_btf_ids, struct, key)
+
+BPF_CALL_1(bpf_request_key_by_id, unsigned long, id)
+{
+ const struct cred *cred = current_cred();
+
+ if (id > (unsigned long)VERIFY_USE_PLATFORM_KEYRING && id != ULONG_MAX)
+ return (unsigned long)NULL;
+
+ if (id == ULONG_MAX)
+ return (unsigned long)cred->session_keyring;
+
+ return id;
+}
+
+static const struct bpf_func_proto bpf_request_key_by_id_proto = {
+ .func = bpf_request_key_by_id,
+ .gpl_only = false,
+ .ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
+ .ret_btf_id = &bpf_request_key_by_id_btf_ids[0],
+ .arg1_type = ARG_ANYTHING,
+};
+#endif /* CONFIG_KEYS */
+
static const struct bpf_func_proto *
bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
@@ -158,6 +184,10 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return prog->aux->sleepable ? &bpf_ima_file_hash_proto : NULL;
case BPF_FUNC_get_attach_cookie:
return bpf_prog_has_trampoline(prog) ? &bpf_get_attach_cookie_proto : NULL;
+#ifdef CONFIG_KEYS
+ case BPF_FUNC_request_key_by_id:
+ return &bpf_request_key_by_id_proto;
+#endif /* CONFIG_KEYS */
default:
return tracing_prog_func_proto(func_id, prog);
}
diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py
index 855b937e7585..176917df0ac0 100755
--- a/scripts/bpf_doc.py
+++ b/scripts/bpf_doc.py
@@ -635,6 +635,7 @@ class PrinterHelpers(Printer):
'struct bpf_timer',
'struct mptcp_sock',
'struct bpf_dynptr',
+ 'struct key',
]
known_types = {
'...',
@@ -686,6 +687,7 @@ class PrinterHelpers(Printer):
'struct bpf_timer',
'struct mptcp_sock',
'struct bpf_dynptr',
+ 'struct key',
}
mapped_types = {
'u8': '__u8',
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index f4009dbdf62d..dfd93e0e0759 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -5249,6 +5249,22 @@ union bpf_attr {
* Pointer to the underlying dynptr data, NULL if the dynptr is
* read-only, if the dynptr is invalid, or if the offset and length
* is out of bounds.
+ *
+ * struct key *bpf_request_key_by_id(unsigned long id)
+ * Description
+ * Request a keyring by *id*.
+ *
+ * *id* can have the following values (some defined in
+ * 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); ULONG_MAX
+ * for the session keyring (for testing purposes).
+ * Return
+ * A non-NULL pointer if *id* is valid and not 0, a NULL pointer
+ * otherwise.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -5455,6 +5471,7 @@ union bpf_attr {
FN(dynptr_read), \
FN(dynptr_write), \
FN(dynptr_data), \
+ FN(request_key_by_id), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
--
2.25.1
\
 
 \ /
  Last update: 2022-06-14 13:55    [W:0.401 / U:0.312 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site