re: bpf: Implement minimal BPF perf link

3 messages, 2 authors, 2021-08-17 · open the first message on its own page

re: bpf: Implement minimal BPF perf link

From: Colin Ian King <hidden>
Date: 2021-08-17 17:36:33

Hi,

Static analysis with Coverity on linux-next has detected a potential
issue with the following commit:

commit b89fbfbb854c9afc3047e8273cc3a694650b802e
Author: Andrii Nakryiko [off-list ref]
Date:   Sun Aug 15 00:05:57 2021 -0700

    bpf: Implement minimal BPF perf link

The analysis is as follows:

2936 static int bpf_perf_link_attach(const union bpf_attr *attr, struct
bpf_prog *prog)
2937 {

    1. var_decl: Declaring variable link_primer without initializer.

2938        struct bpf_link_primer link_primer;
2939        struct bpf_perf_link *link;
2940        struct perf_event *event;
2941        struct file *perf_file;
2942        int err;
2943

    2. Condition attr->link_create.flags, taking false branch.

2944        if (attr->link_create.flags)
2945                return -EINVAL;
2946
2947        perf_file = perf_event_get(attr->link_create.target_fd);

    3. Condition IS_ERR(perf_file), taking false branch.

2948        if (IS_ERR(perf_file))
2949                return PTR_ERR(perf_file);
2950
2951        link = kzalloc(sizeof(*link), GFP_USER);

    4. Condition !link, taking false branch.

2952        if (!link) {
2953                err = -ENOMEM;
2954                goto out_put_file;
2955        }
2956        bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT,
&bpf_perf_link_lops, prog);
2957        link->perf_file = perf_file;
2958
2959        err = bpf_link_prime(&link->link, &link_primer);

    5. Condition err, taking false branch.

2960        if (err) {
2961                kfree(link);
2962                goto out_put_file;
2963        }
2964
2965        event = perf_file->private_data;
2966        err = perf_event_set_bpf_prog(event, prog,
attr->link_create.perf_event.bpf_cookie);

    6. Condition err, taking true branch.
2967        if (err) {
    7. uninit_use_in_call: Using uninitialized value link_primer.fd when
calling bpf_link_cleanup.
    8. uninit_use_in_call: Using uninitialized value link_primer.file
when calling bpf_link_cleanup.
    9. uninit_use_in_call: Using uninitialized value link_primer.id when
calling bpf_link_cleanup.

   Uninitialized pointer read (UNINIT)
   10. uninit_use_in_call: Using uninitialized value link_primer.link
when calling bpf_link_cleanup.

2968                bpf_link_cleanup(&link_primer);
2969                goto out_put_file;
2970        }
2971        /* perf_event_set_bpf_prog() doesn't take its own refcnt on
prog */
2972        bpf_prog_inc(prog);

I'm not 100% sure if these are false-positives, but I thought I should
report the issues as potentially there is a pointer access on an
uninitialized pointer on line 2968.

Colin

Re: bpf: Implement minimal BPF perf link

From: Andrii Nakryiko <hidden>
Date: 2021-08-17 18:57:17

On Tue, Aug 17, 2021 at 10:36 AM Colin Ian King
[off-list ref] wrote:
Hi,

Static analysis with Coverity on linux-next has detected a potential
issue with the following commit:

commit b89fbfbb854c9afc3047e8273cc3a694650b802e
Author: Andrii Nakryiko [off-list ref]
Date:   Sun Aug 15 00:05:57 2021 -0700

    bpf: Implement minimal BPF perf link

The analysis is as follows:

2936 static int bpf_perf_link_attach(const union bpf_attr *attr, struct
bpf_prog *prog)
2937 {

    1. var_decl: Declaring variable link_primer without initializer.

2938        struct bpf_link_primer link_primer;
2939        struct bpf_perf_link *link;
2940        struct perf_event *event;
2941        struct file *perf_file;
2942        int err;
2943

    2. Condition attr->link_create.flags, taking false branch.

2944        if (attr->link_create.flags)
2945                return -EINVAL;
2946
2947        perf_file = perf_event_get(attr->link_create.target_fd);

    3. Condition IS_ERR(perf_file), taking false branch.

2948        if (IS_ERR(perf_file))
2949                return PTR_ERR(perf_file);
2950
2951        link = kzalloc(sizeof(*link), GFP_USER);

    4. Condition !link, taking false branch.

2952        if (!link) {
2953                err = -ENOMEM;
2954                goto out_put_file;
2955        }
2956        bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT,
&bpf_perf_link_lops, prog);
2957        link->perf_file = perf_file;
2958
2959        err = bpf_link_prime(&link->link, &link_primer);

    5. Condition err, taking false branch.

2960        if (err) {
2961                kfree(link);
2962                goto out_put_file;
2963        }
2964
2965        event = perf_file->private_data;
2966        err = perf_event_set_bpf_prog(event, prog,
attr->link_create.perf_event.bpf_cookie);

    6. Condition err, taking true branch.
2967        if (err) {
    7. uninit_use_in_call: Using uninitialized value link_primer.fd when
calling bpf_link_cleanup.
    8. uninit_use_in_call: Using uninitialized value link_primer.file
when calling bpf_link_cleanup.
    9. uninit_use_in_call: Using uninitialized value link_primer.id when
calling bpf_link_cleanup.

   Uninitialized pointer read (UNINIT)
   10. uninit_use_in_call: Using uninitialized value link_primer.link
when calling bpf_link_cleanup.

2968                bpf_link_cleanup(&link_primer);
2969                goto out_put_file;
2970        }
2971        /* perf_event_set_bpf_prog() doesn't take its own refcnt on
prog */
2972        bpf_prog_inc(prog);

I'm not 100% sure if these are false-positives, but I thought I should
report the issues as potentially there is a pointer access on an
uninitialized pointer on line 2968.
Look at bpf_link_prime() implementation. If it succeeds, link_primer
is fully initialized. We use this pattern in many places, this is the
first time someone reports any potential issues with it. It's a bit
strange that Coverity doesn't recognize such a typical output
parameter initialization pattern, tbh. Maybe the global nature of
bpf_link_prime() throws it off (it assumes it can be "overridden"
during linking?) But I double-checked everything twice, all seems to
be good. Zero-initializing link_primer would be a total waste.
Colin

Re: bpf: Implement minimal BPF perf link

From: Colin Ian King <hidden>
Date: 2021-08-17 20:35:03

On 17/08/2021 19:57, Andrii Nakryiko wrote:
On Tue, Aug 17, 2021 at 10:36 AM Colin Ian King
[off-list ref] wrote:
quoted
Hi,

Static analysis with Coverity on linux-next has detected a potential
issue with the following commit:

commit b89fbfbb854c9afc3047e8273cc3a694650b802e
Author: Andrii Nakryiko [off-list ref]
Date:   Sun Aug 15 00:05:57 2021 -0700

    bpf: Implement minimal BPF perf link

The analysis is as follows:

2936 static int bpf_perf_link_attach(const union bpf_attr *attr, struct
bpf_prog *prog)
2937 {

    1. var_decl: Declaring variable link_primer without initializer.

2938        struct bpf_link_primer link_primer;
2939        struct bpf_perf_link *link;
2940        struct perf_event *event;
2941        struct file *perf_file;
2942        int err;
2943

    2. Condition attr->link_create.flags, taking false branch.

2944        if (attr->link_create.flags)
2945                return -EINVAL;
2946
2947        perf_file = perf_event_get(attr->link_create.target_fd);

    3. Condition IS_ERR(perf_file), taking false branch.

2948        if (IS_ERR(perf_file))
2949                return PTR_ERR(perf_file);
2950
2951        link = kzalloc(sizeof(*link), GFP_USER);

    4. Condition !link, taking false branch.

2952        if (!link) {
2953                err = -ENOMEM;
2954                goto out_put_file;
2955        }
2956        bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT,
&bpf_perf_link_lops, prog);
2957        link->perf_file = perf_file;
2958
2959        err = bpf_link_prime(&link->link, &link_primer);

    5. Condition err, taking false branch.

2960        if (err) {
2961                kfree(link);
2962                goto out_put_file;
2963        }
2964
2965        event = perf_file->private_data;
2966        err = perf_event_set_bpf_prog(event, prog,
attr->link_create.perf_event.bpf_cookie);

    6. Condition err, taking true branch.
2967        if (err) {
    7. uninit_use_in_call: Using uninitialized value link_primer.fd when
calling bpf_link_cleanup.
    8. uninit_use_in_call: Using uninitialized value link_primer.file
when calling bpf_link_cleanup.
    9. uninit_use_in_call: Using uninitialized value link_primer.id when
calling bpf_link_cleanup.

   Uninitialized pointer read (UNINIT)
   10. uninit_use_in_call: Using uninitialized value link_primer.link
when calling bpf_link_cleanup.

2968                bpf_link_cleanup(&link_primer);
2969                goto out_put_file;
2970        }
2971        /* perf_event_set_bpf_prog() doesn't take its own refcnt on
prog */
2972        bpf_prog_inc(prog);

I'm not 100% sure if these are false-positives, but I thought I should
report the issues as potentially there is a pointer access on an
uninitialized pointer on line 2968.
Look at bpf_link_prime() implementation. If it succeeds, link_primer
is fully initialized. We use this pattern in many places, this is the
first time someone reports any potential issues with it. It's a bit
strange that Coverity doesn't recognize such a typical output
parameter initialization pattern, tbh. Maybe the global nature of
bpf_link_prime() throws it off (it assumes it can be "overridden"
during linking?) But I double-checked everything twice, all seems to
be good. Zero-initializing link_primer would be a total waste.
Yes, in pedantic mode it can throw false positives, it's not perfect.
Thanks for double checking, and apologies for wasting your valuable time.

Colin
quoted
Colin

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help