bpf: fix some bad __rcu annotations in bpf/core.c
Subsystems (4)
PATCH 1/1 bpf: fix some bad __rcu annotations in bpf/core.c
Sparse shows some "incorrect type" warnings in the bpf core code.
They are caused by bad __rcu annotations:
1) bpf_prog_array_alloc() returns an __rcu pointer, which isn't true. At that moment it's obviously an exclusive "owning" pointer, which is valid for an infinite amount of time, so __rcu is meaningless.
2) The progs local variable in compute_effective_progs should be marked as __bpf too, it's a local variable, not shared with anyone else at all. The real __rcu variable is array pointer, which should be assigned with rcu_assign_pointer.
3) __rcu progs argument of bpf_prog_array_free() should be casted to a simple pointer before calling kfree_rcu().
4) There is a missing rcu_dereference() annotation in bpf_prog_array_copy_to_user().
5) old_array __rcu pointer in bpf_prog_array_copy() is used as a "normal" non-__rcu pointer.
These changes remove the following sparse warnings:kernel/bpf/core.c:1544:31: warning: incorrect type in return expression (different address spaces)kernel/bpf/core.c:1544:31: expected struct bpf_prog_array [noderef] <asn:4>*kernel/bpf/core.c:1544:31: got void *kernel/bpf/core.c:1548:17: warning: incorrect type in return expression (different address spaces)kernel/bpf/core.c:1548:17: expected struct bpf_prog_array [noderef] <asn:4>*kernel/bpf/core.c:1548:17: got struct bpf_prog_array *<noident>kernel/bpf/core.c:1556:9: warning: incorrect type in argument 1 (different address spaces)kernel/bpf/core.c:1556:9: expected struct callback_head *headkernel/bpf/core.c:1556:9: got struct callback_head [noderef] <asn:4>*<noident>kernel/bpf/core.c:1629:34: warning: incorrect type in initializer (different address spaces)kernel/bpf/core.c:1629:34: expected struct bpf_prog **progkernel/bpf/core.c:1629:34: got struct bpf_prog *[noderef] <asn:4>*<noident>kernel/bpf/core.c:1653:31: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1653:31: expected struct bpf_prog **existing_progkernel/bpf/core.c:1653:31: got struct bpf_prog *[noderef] <asn:4>*<noident>kernel/bpf/core.c:1681:15: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1681:15: expected struct bpf_prog_array *arraykernel/bpf/core.c:1681:15: got struct bpf_prog_array [noderef] <asn:4>*kernel/bpf/core.c:1687:31: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1687:31: expected struct bpf_prog **[assigned] existing_progkernel/bpf/core.c:1687:31: got struct bpf_prog *[noderef] <asn:4>*<noident>
--- include/linux/bpf.h | 2 +- kernel/bpf/cgroup.c | 7 +++---- kernel/bpf/core.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-)
include/linux/bpf.h +1 -1
@@ -352,7 +352,7 @@ struct bpf_prog_array {struct bpf_prog *progs[0 ]; }; -struct bpf_prog_array __rcu *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags); +struct bpf_prog_array *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags);void bpf_prog_array_free (struct bpf_prog_array __rcu *progs);int bpf_prog_array_length (struct bpf_prog_array __rcu *progs); int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
kernel/bpf/cgroup.c +3 -4
@@ -95,7 +95,7 @@ static int compute_effective_progs(struct cgroup *cgrp,enum bpf_attach_type type, struct bpf_prog_array __rcu **array) { - struct bpf_prog_array __rcu *progs; + struct bpf_prog_array *progs;struct bpf_prog_list *pl;struct cgroup *p = cgrp;int cnt =0 ;
@@ -120,13 +120,12 @@ static int compute_effective_progs(struct cgroup *cgrp, &p->bpf.progs[type], node) {if (!pl->prog)continue ; -rcu_dereference_protected (progs,1 )-> - progs[cnt++] = pl->prog; + progs->progs[cnt++] = pl->prog; } p =cgroup_parent (p); }while (p); - *array = progs; +rcu_assign_pointer (*array, progs);return 0 ; }
kernel/bpf/core.c +8 -6
@@ -1538,7 +1538,7 @@ static struct { .null_prog = NULL, }; -struct bpf_prog_array __rcu *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags) +struct bpf_prog_array *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags) {if (prog_cnt) return kzalloc(sizeof(struct bpf_prog_array) +
@@ -1550,10 +1550,11 @@ struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags)void bpf_prog_array_free (struct bpf_prog_array __rcu *progs) { -if (!progs || - progs == (struct bpf_prog_array __rcu *)&empty_prog_array.hdr) +struct bpf_prog_array *array =rcu_access_pointer (progs); + +if (!array || array == &empty_prog_array.hdr)return ; -kfree_rcu (progs, rcu); +kfree_rcu (array, rcu); }int bpf_prog_array_length (struct bpf_prog_array __rcu *progs)
@@ -1626,7 +1627,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,void bpf_prog_array_delete_safe (struct bpf_prog_array __rcu *progs,struct bpf_prog *old_prog) { -struct bpf_prog **prog = progs->progs; +struct bpf_prog **prog =rcu_dereference (progs)->progs;for (; *prog; prog++)if (*prog == old_prog) {
@@ -1635,11 +1636,12 @@ void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, } } -int bpf_prog_array_copy (struct bpf_prog_array __rcu *old_array, +int bpf_prog_array_copy (struct bpf_prog_array __rcu *__old_array,struct bpf_prog *exclude_prog,struct bpf_prog *include_prog,struct bpf_prog_array **new_array) { +struct bpf_prog_array *old_array =rcu_access_pointer (__old_array);int new_prog_cnt, carry_prog_cnt =0 ;struct bpf_prog **existing_prog;struct bpf_prog_array *array;
Signature · 1 line
2.14.4
Daniel Borkmann
maintainerHi Roman,
Quoted 1 line · Roman Gushchin
Sparse shows some "incorrect type" warnings in the bpf core code.
Thanks for taking a stab at these! It would really help if you could split the patch into a small series and fix each individual case that is problematic here.
Please also add Fixes tags to the patches.
More below.
Quoted 7 lines
They are caused by bad
__rcuannotations:
1)bpf_prog_array_alloc()returns an__rcupointer, which isn't true. At that moment it's obviously an exclusive "owning" pointer, which is valid for an infinite amount of time, so__rcuis meaningless.
2) The progs local variable incompute_effective_progsshould be marked as__bpftoo, it's a local variable, not shared with anyone
Typo: __bpf ?
kernel/bpf/core.c struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags)
Quoted 97 lines
else at all. The real
__rcuvariable is array pointer, which should be assigned withrcu_assign_pointer.
3)__rcuprogs argument ofbpf_prog_array_free()should be casted to a simple pointer before callingkfree_rcu().
4) There is a missingrcu_dereference()annotation inbpf_prog_array_copy_to_user().
5)old_array__rcupointer inbpf_prog_array_copy()is used as a "normal" non-__rcu pointer.These changes remove the following sparse warnings:
kernel/bpf/core.c:1544:31: warning: incorrect type in return expression (different address spaces)kernel/bpf/core.c:1544:31: expected structbpf_prog_array[noderef] <asn:4>*kernel/bpf/core.c:1544:31: got void *kernel/bpf/core.c:1548:17: warning: incorrect type in return expression (different address spaces)kernel/bpf/core.c:1548:17: expected structbpf_prog_array[noderef] <asn:4>*kernel/bpf/core.c:1548:17: got structbpf_prog_array*<noident>kernel/bpf/core.c:1556:9: warning: incorrect type in argument 1 (different address spaces)kernel/bpf/core.c:1556:9: expected structcallback_head*headkernel/bpf/core.c:1556:9: got structcallback_head[noderef] <asn:4>*<noident>kernel/bpf/core.c:1629:34: warning: incorrect type in initializer (different address spaces)kernel/bpf/core.c:1629:34: expected structbpf_prog**progkernel/bpf/core.c:1629:34: got structbpf_prog*[noderef] <asn:4>*<noident>kernel/bpf/core.c:1653:31: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1653:31: expected structbpf_prog**existing_progkernel/bpf/core.c:1653:31: got structbpf_prog*[noderef] <asn:4>*<noident>kernel/bpf/core.c:1681:15: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1681:15: expected structbpf_prog_array*arraykernel/bpf/core.c:1681:15: got structbpf_prog_array[noderef] <asn:4>*kernel/bpf/core.c:1687:31: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1687:31: expected structbpf_prog**[assigned]existing_progkernel/bpf/core.c:1687:31: got structbpf_prog*[noderef] <asn:4>*<noident>Signed-off-by Roman Gushchin <[email protected]>Cc Daniel Borkmann <[email protected]>Cc Alexei Starovoitov <[email protected]>--- include/linux/bpf.h | 2 +- kernel/bpf/cgroup.c | 7 +++---- kernel/bpf/core.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-)include/linux/bpf.h +1
-1@@ -352,7 +352,7 @@ struct bpf_prog_array {struct bpf_prog *progs[0 ]; }; -struct bpf_prog_array __rcu *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags); +struct bpf_prog_array *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags);void bpf_prog_array_free (struct bpf_prog_array __rcu *progs);int bpf_prog_array_length (struct bpf_prog_array __rcu *progs); int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,kernel/bpf/cgroup.c +3
-4@@ -95,7 +95,7 @@ static int compute_effective_progs(struct cgroup *cgrp,enum bpf_attach_type type, struct bpf_prog_array __rcu **array) { - struct bpf_prog_array __rcu *progs; + struct bpf_prog_array *progs;struct bpf_prog_list *pl;struct cgroup *p = cgrp;int cnt =0 ;@@ -120,13 +120,12 @@ static int compute_effective_progs(struct cgroup *cgrp, &p->bpf.progs[type], node) {if (!pl->prog)continue ; -rcu_dereference_protected (progs,1 )-> - progs[cnt++] = pl->prog; + progs->progs[cnt++] = pl->prog; } p =cgroup_parent (p); }while (p); - *array = progs; +rcu_assign_pointer (*array, progs);return 0 ; }kernel/bpf/core.c +1
-1@@ -1538,7 +1538,7 @@ static struct { .null_prog = NULL, }; -struct bpf_prog_array __rcu *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags) +struct bpf_prog_array *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags) {if (prog_cnt) return kzalloc(sizeof(struct bpf_prog_array) +@@ -1550,10 +1550,11 @@ struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags)
Looks good to me to here.
kernel/bpf/core.c struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) · line 1553
Quoted 5 lines
kernel/bpf/core.c +1
-2void bpf_prog_array_free (struct bpf_prog_array __rcu *progs) { -if (!progs || - progs == (struct bpf_prog_array __rcu *)&empty_prog_array.hdr) +struct bpf_prog_array *array =rcu_access_pointer (progs);
Can you elaborate on the rcu_access_pointer() part? This looks odd, at minimum this needs a comment explaining why it's needed. Is the __rcu annotation above even correct?
Quoted 9 lines
kernel/bpf/core.c +3
-1+ +if (!array || array == &empty_prog_array.hdr)return ; -kfree_rcu (progs, rcu); +kfree_rcu (array, rcu); }int bpf_prog_array_length (struct bpf_prog_array __rcu *progs)
kernel/bpf/core.c int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, · line 1630
Quoted 5 lines
kernel/bpf/core.c +1
-1@@ -1626,7 +1627,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,void bpf_prog_array_delete_safe (struct bpf_prog_array __rcu *progs,struct bpf_prog *old_prog) { -struct bpf_prog **prog = progs->progs; +struct bpf_prog **prog =rcu_dereference (progs)->progs;
Can you elaborate here as well? __rcu annotation buggy instead?
kernel/bpf/core.c void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, · line 1644
Quoted 13 lines
kernel/bpf/core.c +2
-1for (; *prog; prog++)if (*prog == old_prog) {@@ -1635,11 +1636,12 @@ void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, } } -int bpf_prog_array_copy (struct bpf_prog_array __rcu *old_array, +int bpf_prog_array_copy (struct bpf_prog_array __rcu *__old_array,struct bpf_prog *exclude_prog,struct bpf_prog *include_prog,struct bpf_prog_array **new_array) { +struct bpf_prog_array *old_array =rcu_access_pointer (__old_array);
Same comment here, this doesn't look right. We even fetch old_array->progs from it later on in this path.
kernel/bpf/core.c void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, · line 1647
Quoted 4 lines
kernel/bpf/core.c +0
-0int new_prog_cnt, carry_prog_cnt =0 ;struct bpf_prog **existing_prog;struct bpf_prog_array *array;
Thanks,
Daniel
Quoted 10 lines · Daniel Borkmann
Hi Roman,
Quoted 1 line · Roman Gushchin
Sparse shows some "incorrect type" warnings in the bpf core code.
Thanks for taking a stab at these! It would really help if you could split the patch into a small series and fix each individual case that is problematic here.
Please also add Fixes tags to the patches.
Sure.
The only problem which I have with these sparse warnings, is that my cgroup local storage patchset touches some of these lines, and I'm receiving automatic complains.
Quoted 11 lines
More below.
Quoted 7 lines
They are caused by bad
__rcuannotations:
1)bpf_prog_array_alloc()returns an__rcupointer, which isn't true. At that moment it's obviously an exclusive "owning" pointer, which is valid for an infinite amount of time, so__rcuis meaningless.
2) The progs local variable incompute_effective_progsshould be marked as__bpftoo, it's a local variable, not shared with anyone
Quoted 1 line
Typo:
__bpf?
Yep, fixed.
Quoted 101 lines
kernel/bpf/core.c struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags)
Quoted 98 lines
else at all. The real
__rcuvariable is array pointer, which should be assigned withrcu_assign_pointer.
3)__rcuprogs argument ofbpf_prog_array_free()should be casted to a simple pointer before callingkfree_rcu().
4) There is a missingrcu_dereference()annotation inbpf_prog_array_copy_to_user().
5)old_array__rcupointer inbpf_prog_array_copy()is used as a "normal" non-__rcu pointer.These changes remove the following sparse warnings:
kernel/bpf/core.c:1544:31: warning: incorrect type in return expression (different address spaces)kernel/bpf/core.c:1544:31: expected structbpf_prog_array[noderef] <asn:4>*kernel/bpf/core.c:1544:31: got void *kernel/bpf/core.c:1548:17: warning: incorrect type in return expression (different address spaces)kernel/bpf/core.c:1548:17: expected structbpf_prog_array[noderef] <asn:4>*kernel/bpf/core.c:1548:17: got structbpf_prog_array*<noident>kernel/bpf/core.c:1556:9: warning: incorrect type in argument 1 (different address spaces)kernel/bpf/core.c:1556:9: expected structcallback_head*headkernel/bpf/core.c:1556:9: got structcallback_head[noderef] <asn:4>*<noident>kernel/bpf/core.c:1629:34: warning: incorrect type in initializer (different address spaces)kernel/bpf/core.c:1629:34: expected structbpf_prog**progkernel/bpf/core.c:1629:34: got structbpf_prog*[noderef] <asn:4>*<noident>kernel/bpf/core.c:1653:31: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1653:31: expected structbpf_prog**existing_progkernel/bpf/core.c:1653:31: got structbpf_prog*[noderef] <asn:4>*<noident>kernel/bpf/core.c:1681:15: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1681:15: expected structbpf_prog_array*arraykernel/bpf/core.c:1681:15: got structbpf_prog_array[noderef] <asn:4>*kernel/bpf/core.c:1687:31: warning: incorrect type in assignment (different address spaces)kernel/bpf/core.c:1687:31: expected structbpf_prog**[assigned]existing_progkernel/bpf/core.c:1687:31: got structbpf_prog*[noderef] <asn:4>*<noident>Signed-off-by Roman Gushchin <[email protected]>Cc Daniel Borkmann <[email protected]>Cc Alexei Starovoitov <[email protected]>--- include/linux/bpf.h | 2 +- kernel/bpf/cgroup.c | 7 +++---- kernel/bpf/core.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-)include/linux/bpf.h +1
-1@@ -352,7 +352,7 @@ struct bpf_prog_array {struct bpf_prog *progs[0 ]; }; -struct bpf_prog_array __rcu *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags); +struct bpf_prog_array *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags);void bpf_prog_array_free (struct bpf_prog_array __rcu *progs);int bpf_prog_array_length (struct bpf_prog_array __rcu *progs); int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,kernel/bpf/cgroup.c +3
-4@@ -95,7 +95,7 @@ static int compute_effective_progs(struct cgroup *cgrp,enum bpf_attach_type type, struct bpf_prog_array __rcu **array) { - struct bpf_prog_array __rcu *progs; + struct bpf_prog_array *progs;struct bpf_prog_list *pl;struct cgroup *p = cgrp;int cnt =0 ;@@ -120,13 +120,12 @@ static int compute_effective_progs(struct cgroup *cgrp, &p->bpf.progs[type], node) {if (!pl->prog)continue ; -rcu_dereference_protected (progs,1 )-> - progs[cnt++] = pl->prog; + progs->progs[cnt++] = pl->prog; } p =cgroup_parent (p); }while (p); - *array = progs; +rcu_assign_pointer (*array, progs);return 0 ; }kernel/bpf/core.c +1
-1@@ -1538,7 +1538,7 @@ static struct { .null_prog = NULL, }; -struct bpf_prog_array __rcu *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags) +struct bpf_prog_array *bpf_prog_array_alloc (u32 prog_cnt,gfp_t flags) {if (prog_cnt) return kzalloc(sizeof(struct bpf_prog_array) +@@ -1550,10 +1550,11 @@ struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags)Looks good to me to here.
Quoted 9 lines
kernel/bpf/core.c struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) · line 1553
Quoted 5 lines
kernel/bpf/core.c +1
-2void bpf_prog_array_free (struct bpf_prog_array __rcu *progs) { -if (!progs || - progs == (struct bpf_prog_array __rcu *)&empty_prog_array.hdr) +struct bpf_prog_array *array =rcu_access_pointer (progs);Can you elaborate on the
rcu_access_pointer()part? This looks odd, at minimum this needs a comment explaining why it's needed. Is the__rcuannotation above even correct?
No, it's not. But fixing it causes to use rcu_access_pointer() for almost every bpf_prog_array_delete_safe() call. Still better probably, will go this path in v2.
Quoted 8 lines
Quoted 8 lines
kernel/bpf/core.c +3
-1+ +if (!array || array == &empty_prog_array.hdr)return ; -kfree_rcu (progs, rcu); +kfree_rcu (array, rcu); }
Quoted 9 lines
kernel/bpf/core.c int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, · line 1630
Quoted 7 lines
kernel/bpf/core.c +1
-1int bpf_prog_array_length (struct bpf_prog_array __rcu *progs)@@ -1626,7 +1627,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,void bpf_prog_array_delete_safe (struct bpf_prog_array __rcu *progs,struct bpf_prog *old_prog) { -struct bpf_prog **prog = progs->progs; +struct bpf_prog **prog =rcu_dereference (progs)->progs;Can you elaborate here as well?
__rcuannotation buggy instead?
But here it's fine. Please, look at bpf_prog_array_length() and bpf_prog_array_copy_to_user(). Same applies here.
If we want to be more precise, the "progs" field in the bpf_prog_array should also be marked with __rcu, but this is beyond the scope of this patch(set).
Quoted 7 lines
Quoted 7 lines
kernel/bpf/core.c +0
-0for (; *prog; prog++)if (*prog == old_prog) {@@ -1635,11 +1636,12 @@ void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, } }
Quoted 10 lines
kernel/bpf/core.c void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, · line 1644
Quoted 7 lines
kernel/bpf/core.c +2
-1-int bpf_prog_array_copy (struct bpf_prog_array __rcu *old_array, +int bpf_prog_array_copy (struct bpf_prog_array __rcu *__old_array,struct bpf_prog *exclude_prog,struct bpf_prog *include_prog,struct bpf_prog_array **new_array) { +struct bpf_prog_array *old_array =rcu_access_pointer (__old_array);Same comment here, this doesn't look right. We even fetch
old_array->progsfrom it later on in this path.
Same here. old_array->progs field is not marked with __bpf currently.
Thanks!