From: Lorenz Bauer <lmb@cloudflare.com>
To: ast@kernel.org, yhs@fb.com, daniel@iogearbox.net,
jakub@cloudflare.com, john.fastabend@gmail.com, kafai@fb.com
Cc: bpf@vger.kernel.org, kernel-team@cloudflare.com,
Lorenz Bauer <lmb@cloudflare.com>
Subject: [PATCH bpf-next v4 1/7] bpf: Allow passing BTF pointers as PTR_TO_SOCK_COMMON
Date: Mon, 7 Sep 2020 15:46:55 +0100 [thread overview]
Message-ID: <20200907144701.44867-2-lmb@cloudflare.com> (raw)
In-Reply-To: <20200907144701.44867-1-lmb@cloudflare.com>
Tracing programs can derive struct sock pointers from a variety
of sources, e.g. a bpf_iter for sk_storage maps receives one as
part of the context. It's desirable to be able to pass these to
functions that expect PTR_TO_SOCK_COMMON. For example, it enables us
to insert such a socket into a sockmap via map_elem_update.
Note that we can't use struct sock* in cases where a function
expects PTR_TO_SOCKET: not all struct sock* that a tracing program
may derive are indeed for a full socket, code must check the
socket state instead.
Teach the verifier that a PTR_TO_BTF_ID for a struct sock is
equivalent to PTR_TO_SOCK_COMMON. There is one hazard here:
bpf_sk_release also takes a PTR_TO_SOCK_COMMON, but expects it to be
refcounted. Since this isn't the case for pointers derived from
BTF we must prevent them from being passed to the function.
Luckily, we can simply check that the ref_obj_id is not zero
in release_reference, and return an error otherwise.
Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
---
kernel/bpf/verifier.c | 61 +++++++++++++++++++++++++------------------
1 file changed, 36 insertions(+), 25 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b4e9c56b8b32..f1f45ce42d60 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3908,6 +3908,9 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
return 0;
}
+BTF_ID_LIST(btf_sock_common_ids)
+BTF_ID(struct, sock)
+
static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
struct bpf_call_arg_meta *meta,
const struct bpf_func_proto *fn)
@@ -3984,7 +3987,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
} else if (arg_type == ARG_PTR_TO_SOCK_COMMON) {
expected_type = PTR_TO_SOCK_COMMON;
/* Any sk pointer can be ARG_PTR_TO_SOCK_COMMON */
- if (!type_is_sk_pointer(type))
+ if (!type_is_sk_pointer(type) &&
+ type != PTR_TO_BTF_ID)
goto err_type;
if (reg->ref_obj_id) {
if (meta->ref_obj_id) {
@@ -3995,6 +3999,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
}
meta->ref_obj_id = reg->ref_obj_id;
}
+ meta->btf_id = btf_sock_common_ids[0];
} else if (arg_type == ARG_PTR_TO_SOCKET ||
arg_type == ARG_PTR_TO_SOCKET_OR_NULL) {
expected_type = PTR_TO_SOCKET;
@@ -4004,33 +4009,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
goto err_type;
}
} else if (arg_type == ARG_PTR_TO_BTF_ID) {
- bool ids_match = false;
-
expected_type = PTR_TO_BTF_ID;
if (type != expected_type)
goto err_type;
- if (!fn->check_btf_id) {
- if (reg->btf_id != meta->btf_id) {
- ids_match = btf_struct_ids_match(&env->log, reg->off, reg->btf_id,
- meta->btf_id);
- if (!ids_match) {
- verbose(env, "Helper has type %s got %s in R%d\n",
- kernel_type_name(meta->btf_id),
- kernel_type_name(reg->btf_id), regno);
- return -EACCES;
- }
- }
- } else if (!fn->check_btf_id(reg->btf_id, arg)) {
- verbose(env, "Helper does not support %s in R%d\n",
- kernel_type_name(reg->btf_id), regno);
-
- return -EACCES;
- }
- if ((reg->off && !ids_match) || !tnum_is_const(reg->var_off) || reg->var_off.value) {
- verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
- regno);
- return -EACCES;
- }
} else if (arg_type == ARG_PTR_TO_SPIN_LOCK) {
if (meta->func_id == BPF_FUNC_spin_lock) {
if (process_spin_lock(env, regno, true))
@@ -4085,6 +4066,33 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return -EFAULT;
}
+ if (type == PTR_TO_BTF_ID) {
+ bool ids_match = false;
+
+ if (!fn->check_btf_id) {
+ if (reg->btf_id != meta->btf_id) {
+ ids_match = btf_struct_ids_match(&env->log, reg->off, reg->btf_id,
+ meta->btf_id);
+ if (!ids_match) {
+ verbose(env, "Helper has type %s got %s in R%d\n",
+ kernel_type_name(meta->btf_id),
+ kernel_type_name(reg->btf_id), regno);
+ return -EACCES;
+ }
+ }
+ } else if (!fn->check_btf_id(reg->btf_id, arg)) {
+ verbose(env, "Helper does not support %s in R%d\n",
+ kernel_type_name(reg->btf_id), regno);
+
+ return -EACCES;
+ }
+ if ((reg->off && !ids_match) || !tnum_is_const(reg->var_off) || reg->var_off.value) {
+ verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
+ regno);
+ return -EACCES;
+ }
+ }
+
if (arg_type == ARG_CONST_MAP_PTR) {
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
meta->map_ptr = reg->map_ptr;
@@ -4561,6 +4569,9 @@ static int release_reference(struct bpf_verifier_env *env,
int err;
int i;
+ if (!ref_obj_id)
+ return -EINVAL;
+
err = release_reference_state(cur_func(env), ref_obj_id);
if (err)
return err;
--
2.25.1
next prev parent reply other threads:[~2020-09-07 16:04 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-07 14:46 [PATCH bpf-next v4 0/7] Sockmap iterator Lorenz Bauer
2020-09-07 14:46 ` Lorenz Bauer [this message]
2020-09-09 5:07 ` [PATCH bpf-next v4 1/7] bpf: Allow passing BTF pointers as PTR_TO_SOCK_COMMON Martin KaFai Lau
2020-09-07 14:46 ` [PATCH bpf-next v4 2/7] net: sockmap: Remove unnecessary sk_fullsock checks Lorenz Bauer
2020-09-07 14:46 ` [PATCH bpf-next v4 3/7] net: Allow iterating sockmap and sockhash Lorenz Bauer
2020-09-07 14:46 ` [PATCH bpf-next v4 4/7] bpf: sockmap: accept sock_common pointer when updating Lorenz Bauer
2020-09-07 14:46 ` [PATCH bpf-next v4 5/7] selftests: bpf: Ensure that BTF sockets cannot be released Lorenz Bauer
2020-09-07 14:47 ` [PATCH bpf-next v4 6/7] selftests: bpf: Add helper to compare socket cookies Lorenz Bauer
2020-09-07 14:47 ` [PATCH bpf-next v4 7/7] selftests: bpf: Test copying a sockmap via bpf_iter Lorenz Bauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200907144701.44867-2-lmb@cloudflare.com \
--to=lmb@cloudflare.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=jakub@cloudflare.com \
--cc=john.fastabend@gmail.com \
--cc=kafai@fb.com \
--cc=kernel-team@cloudflare.com \
--cc=yhs@fb.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox