Hi,
Static analysis with Coverity on linux-next has detected a potential
issue with the following commit:
commit b89fbfbb854c9afc3047e8273cc3a694650b802e
Author: Andrii Nakryiko <[email protected]>
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
On Tue, Aug 17, 2021 at 10:36 AM Colin Ian King
<[email protected]> wrote:
>
> Hi,
>
> Static analysis with Coverity on linux-next has detected a potential
> issue with the following commit:
>
> commit b89fbfbb854c9afc3047e8273cc3a694650b802e
> Author: Andrii Nakryiko <[email protected]>
> 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
On 17/08/2021 19:57, Andrii Nakryiko wrote:
> On Tue, Aug 17, 2021 at 10:36 AM Colin Ian King
> <[email protected]> wrote:
>>
>> Hi,
>>
>> Static analysis with Coverity on linux-next has detected a potential
>> issue with the following commit:
>>
>> commit b89fbfbb854c9afc3047e8273cc3a694650b802e
>> Author: Andrii Nakryiko <[email protected]>
>> 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
>
>>
>> Colin