[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <5ec2f1a9a9e6a_47112aee592725b435@john-XPS-13-9370.notmuch>
Date: Mon, 18 May 2020 13:35:53 -0700
From: John Fastabend <john.fastabend@...il.com>
To: John Fastabend <john.fastabend@...il.com>, ast@...nel.org,
daniel@...earbox.net
Cc: netdev@...r.kernel.org, bpf@...r.kernel.org,
john.fastabend@...il.com
Subject: RE: [bpf-next PATCH 1/4] bpf: verifier track null pointer
branch_taken with JNE and JEQ
John Fastabend wrote:
> Current verifier when considering which branch may be taken on a
> conditional test with pointer returns -1 meaning either branch may
> be taken. But, we track if pointers can be NULL by using dedicated
> types for valid pointers (pointers that can not be NULL). For example,
> we have PTR_TO_SOCK and PTR_TO_SOCK_OR_NULL to indicate a pointer
> that is valid or not, PTR_TO_SOCK being the validated pointer type.
[...]
> Because at 51->53 jmp verifier promoted reg6 from type PTR_TO_SOCK_OR_NULL
> to PTR_TO_SOCK but then at 62 we still test both paths ignoring that we
> already promoted the type. So we incorrectly conclude an unreleased
> reference. To fix this we add logic in is_branch_taken to test the
> OR_NULL portion of the type and if its not possible for a pointer to
> be NULL we can prune the branch taken where 'r6 == 0x0'.
>
> After the above additional logic is added the C code above passes
> as expected.
>
> This makes the assumption that all pointer types PTR_TO_* that can be null
> have an equivalent type PTR_TO_*_OR_NULL logic.
I can send a v2 to update the last sentence here it is not true with code
below. Initially I thought to negate reg_type_may_be_null() so that the
guard in the branch_taken on this logic was
if (__is_pointer_value(false, reg)) {
if (!reg_type_may_be_null(reg->type))
return -1;
But this pulls in other pointers which are meaningless in this context.
For example PTR_TO_STACK, PTR_TO_BTF_ID, etc. I think its easier to avoid
thinking about these contexts and also safer to just be explicit and
built a new type filter, reg_type_not_null() below. Better name suggestions
welcome.
>
> Suggested-by: Alexei Starovoitov <ast@...nel.org>
> Reported-by: Andrey Ignatov <rdna@...com>
> Signed-off-by: John Fastabend <john.fastabend@...il.com>
> ---
> 0 files changed
With the v2 I'll fix this '0 files changed' issue here messed up my
branch mgmt a bit here when moving patches around.
Will wait a bit though to catch any other feedback.
Thanks,
John
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 180933f..8f576e2 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -393,6 +393,14 @@ static bool type_is_sk_pointer(enum bpf_reg_type type)
> type == PTR_TO_XDP_SOCK;
> }
>
> +static bool reg_type_not_null(enum bpf_reg_type type)
> +{
k> + return type == PTR_TO_SOCKET ||
> + type == PTR_TO_TCP_SOCK ||
> + type == PTR_TO_MAP_VALUE ||
> + type == PTR_TO_SOCK_COMMON;
> +}
> +
> static bool reg_type_may_be_null(enum bpf_reg_type type)
> {
> return type == PTR_TO_MAP_VALUE_OR_NULL ||
> @@ -1970,8 +1978,9 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno,
> if (regno >= 0) {
> reg = &func->regs[regno];
> if (reg->type != SCALAR_VALUE) {
> - WARN_ONCE(1, "backtracing misuse");
> - return -EFAULT;
> + if (unlikely(!reg_type_not_null(reg->type)))
> + WARN_ONCE(1, "backtracing misuse");
> + return 0;
> }
> if (!reg->precise)
> new_marks = true;
> @@ -6306,8 +6315,26 @@ static int is_branch64_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
> static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode,
> bool is_jmp32)
> {
> - if (__is_pointer_value(false, reg))
> - return -1;
> + if (__is_pointer_value(false, reg)) {
> + if (!reg_type_not_null(reg->type))
> + return -1;
> +
> + /* If pointer is valid tests against zero will fail so we can
> + * use this to direct branch taken.
> + */
> + switch (opcode) {
> + case BPF_JEQ:
> + if (val == 0)
> + return 0;
> + return 1;
> + case BPF_JNE:
> + if (val == 0)
> + return 1;
> + return 0;
> + default:
> + return -1;
> + }
> + }
>
> if (is_jmp32)
> return is_branch32_taken(reg, val, opcode);
>
Powered by blists - more mailing lists