[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200923235439.bdi43f3znff67o3n@ast-mbp.dhcp.thefacebook.com>
Date: Wed, 23 Sep 2020 16:54:39 -0700
From: Alexei Starovoitov <alexei.starovoitov@...il.com>
To: Toke Høiland-Jørgensen <toke@...hat.com>
Cc: Alexei Starovoitov <ast@...nel.org>,
Daniel Borkmann <daniel@...earbox.net>,
Martin KaFai Lau <kafai@...com>,
Song Liu <songliubraving@...com>, Yonghong Song <yhs@...com>,
Andrii Nakryiko <andriin@...com>,
John Fastabend <john.fastabend@...il.com>,
Jiri Olsa <jolsa@...hat.com>,
Eelco Chaudron <echaudro@...hat.com>,
KP Singh <kpsingh@...omium.org>, netdev@...r.kernel.org,
bpf@...r.kernel.org
Subject: Re: [PATCH bpf-next v8 03/11] bpf: verifier: refactor
check_attach_btf_id()
On Tue, Sep 22, 2020 at 08:38:37PM +0200, Toke Høiland-Jørgensen wrote:
> From: Toke Høiland-Jørgensen <toke@...hat.com>
>
> The check_attach_btf_id() function really does three things:
>
> 1. It performs a bunch of checks on the program to ensure that the
> attachment is valid.
>
> 2. It stores a bunch of state about the attachment being requested in
> the verifier environment and struct bpf_prog objects.
>
> 3. It allocates a trampoline for the attachment.
>
> This patch splits out (1.) and (3.) into separate functions in preparation
> for reusing them when the actual attachment is happening (in the
> raw_tracepoint_open syscall operation), which will allow tracing programs
> to have multiple (compatible) attachments.
raw_tp_open part is no longer correct.
Also could you re-phrase it that 'stores a bunch of state about the attechment'
is still the case. It doesn't store into bpf_prog directly, but returns instead.
> This also fixes a bug where a bunch of checks were skipped if a trampoline
> already existed for the tracing target.
This time we were lucky. When you see such selftests failures please debug
them before submitting the patches. The reviewers should not be pointing out
that the patch broke some tests.
If anything breaks please mention it in the cover letter.
> -static int check_attach_modify_return(struct bpf_prog *prog, unsigned long addr)
> +static int check_attach_modify_return(const struct bpf_prog *prog, unsigned long addr,
> + const char *func_name)
Since you're adding 'func_name' why keep 'prog' there? Pls drop it.
> {
> if (within_error_injection_list(addr) ||
> - !strncmp(SECURITY_PREFIX, prog->aux->attach_func_name,
> - sizeof(SECURITY_PREFIX) - 1))
> + !strncmp(SECURITY_PREFIX, func_name, sizeof(SECURITY_PREFIX) - 1))
> return 0;
>
> return -EINVAL;
> @@ -11215,43 +11215,29 @@ static int check_non_sleepable_error_inject(u32 btf_id)
> return btf_id_set_contains(&btf_non_sleepable_error_inject, btf_id);
> }
>
> -static int check_attach_btf_id(struct bpf_verifier_env *env)
> +int bpf_check_attach_target(struct bpf_verifier_log *log,
> + const struct bpf_prog *prog,
> + const struct bpf_prog *tgt_prog,
> + u32 btf_id,
> + struct btf_func_model *fmodel,
> + long *tgt_addr,
> + const char **tgt_name,
> + const struct btf_type **tgt_type)
How about grouping the return args into
struct bpf_attach_target_info {
struct btf_func_model fmodel;
long tgt_addr;
const char *tgt_name;
const struct btf_type *tgt_type;
};
allocate it on stack in the caller and pass a pointer into this function?
The same way pass the whole &bpf_attach_target_info into bpf_trampoline_get().
It will use fmodel and tgt_addr out of it, but it doesn't hurt to pass
the whole thing.
Overall I like the refactoring, but this prototype and conditional
if (tgt_name) *tgt_name =; and if (tgt_type) makes it harder to comprehend.
> if (!tgt_prog->jited) {
> bpf_log(log, "Can attach to only JITed progs\n");
> @@ -11328,13 +11312,11 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
> bpf_log(log, "Cannot extend fentry/fexit\n");
> return -EINVAL;
> }
> - key = ((u64)aux->id) << 32 | btf_id;
Could you please refactor key computation into a helper as well?
Especially since it will be used out of verifier.c and from syscall.c.
Something like this for bpf.h
static inline u64 bpf_trampoline_compute_key(struct bpf_prog *tgt_prog, u32 btf_id)
{
if (tgt_prog) {
return ((u64)tgt_prog->aux->id) << 32 | btf_id;
} else {
return btf_id;
}
}
> + ret = bpf_check_attach_target(&env->log, prog, tgt_prog, btf_id,
> + &fmodel, &addr, &tname, &t);
> + if (ret)
> return ret;
> +
> + if (tgt_prog) {
> + if (prog->type == BPF_PROG_TYPE_EXT) {
> + env->ops = bpf_verifier_ops[tgt_prog->type];
> + prog->expected_attach_type =
> + tgt_prog->expected_attach_type;
> + }
> + key = ((u64)tgt_prog->aux->id) << 32 | btf_id;
> + } else {
> + key = btf_id;
> }
and here it would be:
if (tgt_prog && prog->type == BPF_PROG_TYPE_EXT) {
env->ops = bpf_verifier_ops[tgt_prog->type];
prog->expected_attach_type = tgt_prog->expected_attach_type;
}
key = bpf_trampoline_compute_key(tgt_prog, btf_id);
otherwise above 'if' groups two separate things.
It's not pretty in the existing code, no doubt, but since you're doing
nice cleanup let's make it clean here too.
> +
> + /* remember two read only pointers that are valid for
> + * the life time of the kernel
> + */
Here this comment is not correct.
It was correct in the place you copy-pasted it from, but not here.
Please think it through and adjust accordingly.
Powered by blists - more mailing lists