* [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate()
@ 2026-07-09 18:27 Nicholas Dudar
2026-07-09 18:27 ` [PATCH bpf-next v3 1/2] bpf: Require a BPF " Nicholas Dudar
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Nicholas Dudar @ 2026-07-09 18:27 UTC (permalink / raw)
To: ast, daniel, andrii, eddyz87, memxor
Cc: tj, void, arighi, changwoo, bpf, sched-ext
bpf_cpumask_populate() writes its destination with bitmap_copy() but
types it as struct cpumask *, so the verifier accepts a borrowed,
read-only cpumask (for example from scx_bpf_get_online_cpumask()) as a
writable destination. Fix it and add a selftest for coverage.
Changelog:
----------
v2 -> v3 (v1/v2 were a private report to security@kernel.org)
* Split the fix and selftest into separate patches.
* Target bpf-next instead of bpf.
Nicholas Dudar (2):
bpf: Require a BPF cpumask for bpf_cpumask_populate()
selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask
kernel/bpf/cpumask.c | 6 ++---
tools/sched_ext/include/scx/compat.bpf.h | 2 +-
.../selftests/bpf/progs/cpumask_common.h | 2 +-
.../selftests/bpf/progs/cpumask_failure.c | 23 +++++++++++++++++--
.../selftests/bpf/progs/cpumask_success.c | 6 ++---
5 files changed, 29 insertions(+), 10 deletions(-)
base-commit: 36ffa86c42f91c8a57071e024afc4ffb51a8958f
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-09 18:27 [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Nicholas Dudar @ 2026-07-09 18:27 ` Nicholas Dudar 2026-07-09 18:39 ` sashiko-bot 2026-07-10 23:42 ` Emil Tsalapatis 2026-07-09 18:28 ` [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask Nicholas Dudar ` (2 subsequent siblings) 3 siblings, 2 replies; 13+ messages in thread From: Nicholas Dudar @ 2026-07-09 18:27 UTC (permalink / raw) To: ast, daniel, andrii, eddyz87, memxor Cc: tj, void, arighi, changwoo, bpf, sched-ext bpf_cpumask_populate() writes to its destination with bitmap_copy(), but the destination is typed as struct cpumask *. That allows the verifier to accept borrowed cpumask pointers returned by read-only kfuncs, such as scx_bpf_get_online_cpumask(), as a writable destination. Make the destination a struct bpf_cpumask * so populate follows the same ownership rule as the other mutating cpumask kfuncs. Query kfuncs continue to accept const struct cpumask * inputs. Fixes: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits") Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> Assisted-by: Claude:claude-opus-4-8 --- kernel/bpf/cpumask.c | 6 +++--- tools/sched_ext/include/scx/compat.bpf.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c index b8c805b4b06a..1336a4efa755 100644 --- a/kernel/bpf/cpumask.c +++ b/kernel/bpf/cpumask.c @@ -449,12 +449,12 @@ __bpf_kfunc u32 bpf_cpumask_weight(const struct cpumask *cpumask) * @src__sz: Length of the BPF memory region in bytes. * * Return: - * * 0 if the struct cpumask * instance was populated successfully. + * * 0 if the struct bpf_cpumask * instance was populated successfully. * * -EACCES if the memory region is too small to populate the cpumask. * * -EINVAL if the memory region is not aligned to the size of a long * and the architecture does not support efficient unaligned accesses. */ -__bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) +__bpf_kfunc int bpf_cpumask_populate(struct bpf_cpumask *cpumask, void *src, size_t src__sz) { unsigned long source = (unsigned long)src; @@ -467,7 +467,7 @@ __bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t !IS_ALIGNED(source, sizeof(long))) return -EINVAL; - bitmap_copy(cpumask_bits(cpumask), src, nr_cpu_ids); + bitmap_copy(cpumask_bits(&cpumask->cpumask), src, nr_cpu_ids); return 0; } diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h index 87f15f296234..3f74d522f7e7 100644 --- a/tools/sched_ext/include/scx/compat.bpf.h +++ b/tools/sched_ext/include/scx/compat.bpf.h @@ -84,7 +84,7 @@ bool scx_bpf_dispatch_vtime_from_dsq___old(struct bpf_iter_scx_dsq *it__iter, st * * Compat macro will be dropped on v6.19 release. */ -int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak; +int bpf_cpumask_populate(struct bpf_cpumask *dst, void *src, size_t src__sz) __ksym __weak; #define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz) \ (bpf_ksym_exists(bpf_cpumask_populate) ? \ -- 2.34.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-09 18:27 ` [PATCH bpf-next v3 1/2] bpf: Require a BPF " Nicholas Dudar @ 2026-07-09 18:39 ` sashiko-bot 2026-07-10 19:18 ` Kumar Kartikeya Dwivedi 2026-07-10 23:42 ` Emil Tsalapatis 1 sibling, 1 reply; 13+ messages in thread From: sashiko-bot @ 2026-07-09 18:39 UTC (permalink / raw) To: Nicholas Dudar; +Cc: bpf, sched-ext Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The BPF selftests and their headers were not updated to reflect the new `struct bpf_cpumask *` signature for `bpf_cpumask_populate()`. -- --- Patch [1]: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() --- commit 79080c077263fb184f42fe92f3d8db1f3967a4b5 Author: Nicholas Dudar <main.kalliope@gmail.com> bpf: Require a BPF cpumask for bpf_cpumask_populate() This commit changes the first argument of bpf_cpumask_populate() to require a struct bpf_cpumask pointer instead of a struct cpumask pointer. This ensures the function follows the same ownership rules as other mutating cpumask kfuncs. > diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c > index b8c805b4b06a0..1336a4efa7553 100644 > --- a/kernel/bpf/cpumask.c > +++ b/kernel/bpf/cpumask.c [ ... ] > @@ -467,7 +467,7 @@ __bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t > !IS_ALIGNED(source, sizeof(long))) > return -EINVAL; > > - bitmap_copy(cpumask_bits(cpumask), src, nr_cpu_ids); > + bitmap_copy(cpumask_bits(&cpumask->cpumask), src, nr_cpu_ids); > > return 0; > } > diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h > index 87f15f2962348..3f74d522f7e79 100644 > --- a/tools/sched_ext/include/scx/compat.bpf.h > +++ b/tools/sched_ext/include/scx/compat.bpf.h > @@ -84,7 +84,7 @@ bool scx_bpf_dispatch_vtime_from_dsq___old(struct bpf_iter_scx_dsq *it__iter, st > * > * Compat macro will be dropped on v6.19 release. > */ > -int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak; > +int bpf_cpumask_populate(struct bpf_cpumask *dst, void *src, size_t src__sz) __ksym __weak; [Severity: Low] This isn't a bug, but should the BPF selftest headers also be updated to reflect this new signature? Looking at tools/testing/selftests/bpf/progs/cpumask_common.h, it appears it still declares the old signature for the kfunc: int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; Because of this, the tests in cpumask_success.c and cpumask_failure.c under tools/testing/selftests/bpf/progs/ continue to use explicit C-level casts from struct bpf_cpumask * to struct cpumask *. For example, in test_populate_success(): ret = bpf_cpumask_populate((struct cpumask *)mask, bits, CPUMASK_TEST_MASKLEN); While this doesn't cause runtime failures since the BPF verifier matches the runtime register BTF type instead of C-level casts, updating the selftests would ensure complete consistency with the new kfunc signature. -- Sashiko AI review · https://sashiko.dev/#/patchset/20260709182800.2037938-1-main.kalliope@gmail.com?part=1 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-09 18:39 ` sashiko-bot @ 2026-07-10 19:18 ` Kumar Kartikeya Dwivedi 2026-07-10 20:17 ` Admin 0 siblings, 1 reply; 13+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-10 19:18 UTC (permalink / raw) To: sashiko-reviews, Nicholas Dudar; +Cc: bpf, sched-ext On Thu Jul 9, 2026 at 8:39 PM CEST, sashiko-bot wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [Low] The BPF selftests and their headers were not updated to reflect the new `struct bpf_cpumask *` signature for `bpf_cpumask_populate()`. > -- > > --- Patch [1]: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() --- > commit 79080c077263fb184f42fe92f3d8db1f3967a4b5 > Author: Nicholas Dudar <main.kalliope@gmail.com> > > bpf: Require a BPF cpumask for bpf_cpumask_populate() > > This commit changes the first argument of bpf_cpumask_populate() to require > a struct bpf_cpumask pointer instead of a struct cpumask pointer. This > ensures the function follows the same ownership rules as other mutating > cpumask kfuncs. > >> diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c >> index b8c805b4b06a0..1336a4efa7553 100644 >> --- a/kernel/bpf/cpumask.c >> +++ b/kernel/bpf/cpumask.c > [ ... ] >> @@ -467,7 +467,7 @@ __bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t >> !IS_ALIGNED(source, sizeof(long))) >> return -EINVAL; >> >> - bitmap_copy(cpumask_bits(cpumask), src, nr_cpu_ids); >> + bitmap_copy(cpumask_bits(&cpumask->cpumask), src, nr_cpu_ids); >> >> return 0; >> } >> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h >> index 87f15f2962348..3f74d522f7e79 100644 >> --- a/tools/sched_ext/include/scx/compat.bpf.h >> +++ b/tools/sched_ext/include/scx/compat.bpf.h >> @@ -84,7 +84,7 @@ bool scx_bpf_dispatch_vtime_from_dsq___old(struct bpf_iter_scx_dsq *it__iter, st >> * >> * Compat macro will be dropped on v6.19 release. >> */ >> -int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak; >> +int bpf_cpumask_populate(struct bpf_cpumask *dst, void *src, size_t src__sz) __ksym __weak; > > [Severity: Low] > This isn't a bug, but should the BPF selftest headers also be updated to > reflect this new signature? > > Looking at tools/testing/selftests/bpf/progs/cpumask_common.h, it appears it > still declares the old signature for the kfunc: > > int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; > > Because of this, the tests in cpumask_success.c and cpumask_failure.c under > tools/testing/selftests/bpf/progs/ continue to use explicit C-level casts > from struct bpf_cpumask * to struct cpumask *. For example, in > test_populate_success(): > > ret = bpf_cpumask_populate((struct cpumask *)mask, bits, CPUMASK_TEST_MASKLEN); > > While this doesn't cause runtime failures since the BPF verifier matches the > runtime register BTF type instead of C-level casts, updating the selftests > would ensure complete consistency with the new kfunc signature. Once this lands, please send a follow up to address this. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-10 19:18 ` Kumar Kartikeya Dwivedi @ 2026-07-10 20:17 ` Admin 2026-07-10 20:34 ` Kumar Kartikeya Dwivedi 0 siblings, 1 reply; 13+ messages in thread From: Admin @ 2026-07-10 20:17 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi; +Cc: sashiko-reviews, bpf, sched-ext On Fri, Jul 10, 2026 at 3:18 PM Kumar Kartikeya Dwivedi <memxor@gmail.com> wrote: > Once this lands, please send a follow up to address this. Thanks. Patch 2/2 covers this, which updates the cpumask_common.h declaration to take struct bpf_cpumask *, drops the struct cpumask * casts from the existing populate tests, and adds the borrowed-destination rejection test. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-10 20:17 ` Admin @ 2026-07-10 20:34 ` Kumar Kartikeya Dwivedi 2026-07-10 23:43 ` Emil Tsalapatis 0 siblings, 1 reply; 13+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-10 20:34 UTC (permalink / raw) To: Admin; +Cc: sashiko-reviews, bpf, sched-ext On Fri, 10 Jul 2026 at 22:17, Admin <main.kalliope@gmail.com> wrote: > > On Fri, Jul 10, 2026 at 3:18 PM Kumar Kartikeya Dwivedi > <memxor@gmail.com> wrote: > > Once this lands, please send a follow up to address this. > > Thanks. Patch 2/2 covers this, which updates the cpumask_common.h > declaration to take struct bpf_cpumask *, drops > the struct cpumask * casts from the existing populate tests, and adds > the borrowed-destination rejection test. Ah, my bad, makes sense. Let's just wait for others to ack it then. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-10 20:34 ` Kumar Kartikeya Dwivedi @ 2026-07-10 23:43 ` Emil Tsalapatis 0 siblings, 0 replies; 13+ messages in thread From: Emil Tsalapatis @ 2026-07-10 23:43 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi, Admin; +Cc: sashiko-reviews, bpf, sched-ext On Fri Jul 10, 2026 at 4:34 PM EDT, Kumar Kartikeya Dwivedi wrote: > On Fri, 10 Jul 2026 at 22:17, Admin <main.kalliope@gmail.com> wrote: >> >> On Fri, Jul 10, 2026 at 3:18 PM Kumar Kartikeya Dwivedi >> <memxor@gmail.com> wrote: >> > Once this lands, please send a follow up to address this. >> >> Thanks. Patch 2/2 covers this, which updates the cpumask_common.h >> declaration to take struct bpf_cpumask *, drops >> the struct cpumask * casts from the existing populate tests, and adds >> the borrowed-destination rejection test. > > Ah, my bad, makes sense. Let's just wait for others to ack it then. Patchset looks good to me, and is consistent with the "mutation requires passing bpf_cpumask, reading requires plain cpumask" throughout the file. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() 2026-07-09 18:27 ` [PATCH bpf-next v3 1/2] bpf: Require a BPF " Nicholas Dudar 2026-07-09 18:39 ` sashiko-bot @ 2026-07-10 23:42 ` Emil Tsalapatis 1 sibling, 0 replies; 13+ messages in thread From: Emil Tsalapatis @ 2026-07-10 23:42 UTC (permalink / raw) To: Nicholas Dudar, ast, daniel, andrii, eddyz87, memxor Cc: tj, void, arighi, changwoo, bpf, sched-ext On Thu Jul 9, 2026 at 2:27 PM EDT, Nicholas Dudar wrote: > bpf_cpumask_populate() writes to its destination with bitmap_copy(), but > the destination is typed as struct cpumask *. That allows the verifier to > accept borrowed cpumask pointers returned by read-only kfuncs, such as > scx_bpf_get_online_cpumask(), as a writable destination. > > Make the destination a struct bpf_cpumask * so populate follows the same > ownership rule as the other mutating cpumask kfuncs. Query kfuncs continue > to accept const struct cpumask * inputs. > > Fixes: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits") > Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> > Assisted-by: Claude:claude-opus-4-8 Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> > --- > kernel/bpf/cpumask.c | 6 +++--- > tools/sched_ext/include/scx/compat.bpf.h | 2 +- > 2 files changed, 4 insertions(+), 4 deletions(-) > > diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c > index b8c805b4b06a..1336a4efa755 100644 > --- a/kernel/bpf/cpumask.c > +++ b/kernel/bpf/cpumask.c > @@ -449,12 +449,12 @@ __bpf_kfunc u32 bpf_cpumask_weight(const struct cpumask *cpumask) > * @src__sz: Length of the BPF memory region in bytes. > * > * Return: > - * * 0 if the struct cpumask * instance was populated successfully. > + * * 0 if the struct bpf_cpumask * instance was populated successfully. > * * -EACCES if the memory region is too small to populate the cpumask. > * * -EINVAL if the memory region is not aligned to the size of a long > * and the architecture does not support efficient unaligned accesses. > */ > -__bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) > +__bpf_kfunc int bpf_cpumask_populate(struct bpf_cpumask *cpumask, void *src, size_t src__sz) > { > unsigned long source = (unsigned long)src; > > @@ -467,7 +467,7 @@ __bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t > !IS_ALIGNED(source, sizeof(long))) > return -EINVAL; > > - bitmap_copy(cpumask_bits(cpumask), src, nr_cpu_ids); > + bitmap_copy(cpumask_bits(&cpumask->cpumask), src, nr_cpu_ids); > > return 0; > } > diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h > index 87f15f296234..3f74d522f7e7 100644 > --- a/tools/sched_ext/include/scx/compat.bpf.h > +++ b/tools/sched_ext/include/scx/compat.bpf.h > @@ -84,7 +84,7 @@ bool scx_bpf_dispatch_vtime_from_dsq___old(struct bpf_iter_scx_dsq *it__iter, st > * > * Compat macro will be dropped on v6.19 release. > */ > -int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak; > +int bpf_cpumask_populate(struct bpf_cpumask *dst, void *src, size_t src__sz) __ksym __weak; > > #define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz) \ > (bpf_ksym_exists(bpf_cpumask_populate) ? \ ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask 2026-07-09 18:27 [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Nicholas Dudar 2026-07-09 18:27 ` [PATCH bpf-next v3 1/2] bpf: Require a BPF " Nicholas Dudar @ 2026-07-09 18:28 ` Nicholas Dudar 2026-07-10 23:51 ` Emil Tsalapatis 2026-07-10 19:17 ` [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Kumar Kartikeya Dwivedi 2026-07-11 0:00 ` patchwork-bot+netdevbpf 3 siblings, 1 reply; 13+ messages in thread From: Nicholas Dudar @ 2026-07-09 18:28 UTC (permalink / raw) To: ast, daniel, andrii, eddyz87, memxor Cc: tj, void, arighi, changwoo, bpf, sched-ext bpf_cpumask_populate() now takes a struct bpf_cpumask *, so update the kfunc declaration and drop the struct cpumask * casts in the existing populate tests. Add test_populate_borrowed_destination, which passes a borrowed task->cpus_ptr and asserts the verifier rejects it as a writable destination. Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> Assisted-by: Claude:claude-opus-4-8 --- .../selftests/bpf/progs/cpumask_common.h | 2 +- .../selftests/bpf/progs/cpumask_failure.c | 23 +++++++++++++++++-- .../selftests/bpf/progs/cpumask_success.c | 6 ++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index 86085b79f5ca..8fe01308d210 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -61,7 +61,7 @@ u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym __weak; u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym __weak; u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym __weak; -int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; +int bpf_cpumask_populate(struct bpf_cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; void bpf_rcu_read_lock(void) __ksym __weak; void bpf_rcu_read_unlock(void) __ksym __weak; diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c index 4c45346fe6f7..74b4cd4bcdbb 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_failure.c +++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c @@ -231,7 +231,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl u64 bits; int ret; - ret = bpf_cpumask_populate((struct cpumask *)invalid, &bits, sizeof(bits)); + ret = bpf_cpumask_populate(invalid, &bits, sizeof(bits)); if (!ret) err = 2; @@ -252,7 +252,7 @@ int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_f return 0; } - ret = bpf_cpumask_populate((struct cpumask *)local, garbage, 8); + ret = bpf_cpumask_populate(local, garbage, 8); if (!ret) err = 2; @@ -260,3 +260,22 @@ int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_f return 0; } + +SEC("tp_btf/task_newtask") +__failure __msg("expected pointer to STRUCT bpf_cpumask but R1 has a pointer to STRUCT cpumask") +int BPF_PROG(test_populate_borrowed_destination, struct task_struct *task, u64 clone_flags) +{ + u64 bits; + int ret; + + /* + * task->cpus_ptr is a borrowed, read-only struct cpumask *, not an + * owned struct bpf_cpumask *. The verifier must reject it as a + * writable destination for bpf_cpumask_populate(). + */ + ret = bpf_cpumask_populate((struct bpf_cpumask *)task->cpus_ptr, &bits, sizeof(bits)); + if (!ret) + err = 2; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 774706e7b058..36f77b9732d4 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -785,7 +785,7 @@ int BPF_PROG(test_populate_reject_small_mask, struct task_struct *task, u64 clon return 0; /* The kfunc should prevent this operation */ - ret = bpf_cpumask_populate((struct cpumask *)local, &toofewbits, sizeof(toofewbits)); + ret = bpf_cpumask_populate(local, &toofewbits, sizeof(toofewbits)); if (ret != -EACCES) err = 2; @@ -824,7 +824,7 @@ int BPF_PROG(test_populate_reject_unaligned, struct task_struct *task, u64 clone /* Misalign the source array by a byte. */ src = &((char *)bits)[1]; - ret = bpf_cpumask_populate((struct cpumask *)mask, src, CPUMASK_TEST_MASKLEN); + ret = bpf_cpumask_populate(mask, src, CPUMASK_TEST_MASKLEN); if (ret != -EINVAL) err = 2; @@ -855,7 +855,7 @@ int BPF_PROG(test_populate, struct task_struct *task, u64 clone_flags) } /* Pass the entire bits array, the kfunc will only copy the valid bits. */ - ret = bpf_cpumask_populate((struct cpumask *)mask, bits, CPUMASK_TEST_MASKLEN); + ret = bpf_cpumask_populate(mask, bits, CPUMASK_TEST_MASKLEN); if (ret) { err = 2; goto out; -- 2.34.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask 2026-07-09 18:28 ` [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask Nicholas Dudar @ 2026-07-10 23:51 ` Emil Tsalapatis 0 siblings, 0 replies; 13+ messages in thread From: Emil Tsalapatis @ 2026-07-10 23:51 UTC (permalink / raw) To: Nicholas Dudar, ast, daniel, andrii, eddyz87, memxor Cc: tj, void, arighi, changwoo, bpf, sched-ext On Thu Jul 9, 2026 at 2:28 PM EDT, Nicholas Dudar wrote: > bpf_cpumask_populate() now takes a struct bpf_cpumask *, so update the > kfunc declaration and drop the struct cpumask * casts in the existing > populate tests. Add test_populate_borrowed_destination, which passes a > borrowed task->cpus_ptr and asserts the verifier rejects it as a writable > destination. > > Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> > Assisted-by: Claude:claude-opus-4-8 Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> One thing that'd be nice is an explicit test that checks modifying the cpumask being returned by scx_bpf_get_idle_cpumask, since this was the motivation in the first place. But we don't have a sched_ext test in selftests/bpf, so it's not worth the complexity. Since what we're really testing is that bpf_cpumask -> cpumask conversions are acceptable but not the opposite, I think the tp test suffices. > --- > .../selftests/bpf/progs/cpumask_common.h | 2 +- > .../selftests/bpf/progs/cpumask_failure.c | 23 +++++++++++++++++-- > .../selftests/bpf/progs/cpumask_success.c | 6 ++--- > 3 files changed, 25 insertions(+), 6 deletions(-) > > diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h > index 86085b79f5ca..8fe01308d210 100644 > --- a/tools/testing/selftests/bpf/progs/cpumask_common.h > +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h > @@ -61,7 +61,7 @@ u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym __weak; > u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, > const struct cpumask *src2) __ksym __weak; > u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym __weak; > -int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; > +int bpf_cpumask_populate(struct bpf_cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; > > void bpf_rcu_read_lock(void) __ksym __weak; > void bpf_rcu_read_unlock(void) __ksym __weak; > diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c > index 4c45346fe6f7..74b4cd4bcdbb 100644 > --- a/tools/testing/selftests/bpf/progs/cpumask_failure.c > +++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c > @@ -231,7 +231,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl > u64 bits; > int ret; > > - ret = bpf_cpumask_populate((struct cpumask *)invalid, &bits, sizeof(bits)); > + ret = bpf_cpumask_populate(invalid, &bits, sizeof(bits)); > if (!ret) > err = 2; > > @@ -252,7 +252,7 @@ int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_f > return 0; > } > > - ret = bpf_cpumask_populate((struct cpumask *)local, garbage, 8); > + ret = bpf_cpumask_populate(local, garbage, 8); > if (!ret) > err = 2; > > @@ -260,3 +260,22 @@ int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_f > > return 0; > } > + > +SEC("tp_btf/task_newtask") > +__failure __msg("expected pointer to STRUCT bpf_cpumask but R1 has a pointer to STRUCT cpumask") > +int BPF_PROG(test_populate_borrowed_destination, struct task_struct *task, u64 clone_flags) > +{ > + u64 bits; > + int ret; > + > + /* > + * task->cpus_ptr is a borrowed, read-only struct cpumask *, not an > + * owned struct bpf_cpumask *. The verifier must reject it as a > + * writable destination for bpf_cpumask_populate(). > + */ > + ret = bpf_cpumask_populate((struct bpf_cpumask *)task->cpus_ptr, &bits, sizeof(bits)); > + if (!ret) > + err = 2; > + > + return 0; > +} > diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c > index 774706e7b058..36f77b9732d4 100644 > --- a/tools/testing/selftests/bpf/progs/cpumask_success.c > +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c > @@ -785,7 +785,7 @@ int BPF_PROG(test_populate_reject_small_mask, struct task_struct *task, u64 clon > return 0; > > /* The kfunc should prevent this operation */ > - ret = bpf_cpumask_populate((struct cpumask *)local, &toofewbits, sizeof(toofewbits)); > + ret = bpf_cpumask_populate(local, &toofewbits, sizeof(toofewbits)); > if (ret != -EACCES) > err = 2; > > @@ -824,7 +824,7 @@ int BPF_PROG(test_populate_reject_unaligned, struct task_struct *task, u64 clone > /* Misalign the source array by a byte. */ > src = &((char *)bits)[1]; > > - ret = bpf_cpumask_populate((struct cpumask *)mask, src, CPUMASK_TEST_MASKLEN); > + ret = bpf_cpumask_populate(mask, src, CPUMASK_TEST_MASKLEN); > if (ret != -EINVAL) > err = 2; > > @@ -855,7 +855,7 @@ int BPF_PROG(test_populate, struct task_struct *task, u64 clone_flags) > } > > /* Pass the entire bits array, the kfunc will only copy the valid bits. */ > - ret = bpf_cpumask_populate((struct cpumask *)mask, bits, CPUMASK_TEST_MASKLEN); > + ret = bpf_cpumask_populate(mask, bits, CPUMASK_TEST_MASKLEN); > if (ret) { > err = 2; > goto out; ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() 2026-07-09 18:27 [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Nicholas Dudar 2026-07-09 18:27 ` [PATCH bpf-next v3 1/2] bpf: Require a BPF " Nicholas Dudar 2026-07-09 18:28 ` [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask Nicholas Dudar @ 2026-07-10 19:17 ` Kumar Kartikeya Dwivedi 2026-07-11 23:38 ` Tejun Heo 2026-07-11 0:00 ` patchwork-bot+netdevbpf 3 siblings, 1 reply; 13+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-10 19:17 UTC (permalink / raw) To: Nicholas Dudar, ast, daniel, andrii, eddyz87, memxor, emil Cc: tj, void, arighi, changwoo, bpf, sched-ext On Thu Jul 9, 2026 at 8:27 PM CEST, Nicholas Dudar wrote: > bpf_cpumask_populate() writes its destination with bitmap_copy() but > types it as struct cpumask *, so the verifier accepts a borrowed, > read-only cpumask (for example from scx_bpf_get_online_cpumask()) as a > writable destination. Fix it and add a selftest for coverage. > +To Emil Hi sched-ext folks, this fix looks good to me and on cursory look, apart from potential signature change which may require some adjustment to casts, it should not break existing intendended usage. Could others confirm this? Thanks > [...] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() 2026-07-10 19:17 ` [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Kumar Kartikeya Dwivedi @ 2026-07-11 23:38 ` Tejun Heo 0 siblings, 0 replies; 13+ messages in thread From: Tejun Heo @ 2026-07-11 23:38 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi Cc: Nicholas Dudar, ast, daniel, andrii, eddyz87, emil, void, arighi, changwoo, bpf, sched-ext Hello, On Fri, Jul 10, 2026 at 09:17:08PM +0200, Kumar Kartikeya Dwivedi wrote: > Hi sched-ext folks, this fix looks good to me and on cursory look, apart from > potential signature change which may require some adjustment to casts, it should > not break existing intendended usage. > > Could others confirm this? Thanks AFAICS, this shouldn't break anything. Acked-by: Tejun Heo <tj@kernel.org> Thanks. -- tejun ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() 2026-07-09 18:27 [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Nicholas Dudar ` (2 preceding siblings ...) 2026-07-10 19:17 ` [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Kumar Kartikeya Dwivedi @ 2026-07-11 0:00 ` patchwork-bot+netdevbpf 3 siblings, 0 replies; 13+ messages in thread From: patchwork-bot+netdevbpf @ 2026-07-11 0:00 UTC (permalink / raw) To: Admin Cc: ast, daniel, andrii, eddyz87, memxor, tj, void, arighi, changwoo, bpf, sched-ext Hello: This series was applied to bpf/bpf-next.git (master) by Kumar Kartikeya Dwivedi <memxor@gmail.com>: On Thu, 9 Jul 2026 14:27:58 -0400 you wrote: > bpf_cpumask_populate() writes its destination with bitmap_copy() but > types it as struct cpumask *, so the verifier accepts a borrowed, > read-only cpumask (for example from scx_bpf_get_online_cpumask()) as a > writable destination. Fix it and add a selftest for coverage. > > Changelog: > > [...] Here is the summary with links: - [bpf-next,v3,1/2] bpf: Require a BPF cpumask for bpf_cpumask_populate() https://git.kernel.org/bpf/bpf-next/c/63a704c8b369 - [bpf-next,v3,2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask https://git.kernel.org/bpf/bpf-next/c/5aaad4d9fe9f You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-07-11 23:39 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-09 18:27 [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Nicholas Dudar 2026-07-09 18:27 ` [PATCH bpf-next v3 1/2] bpf: Require a BPF " Nicholas Dudar 2026-07-09 18:39 ` sashiko-bot 2026-07-10 19:18 ` Kumar Kartikeya Dwivedi 2026-07-10 20:17 ` Admin 2026-07-10 20:34 ` Kumar Kartikeya Dwivedi 2026-07-10 23:43 ` Emil Tsalapatis 2026-07-10 23:42 ` Emil Tsalapatis 2026-07-09 18:28 ` [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask Nicholas Dudar 2026-07-10 23:51 ` Emil Tsalapatis 2026-07-10 19:17 ` [PATCH bpf-next v3 0/2] bpf: require an owned cpumask for bpf_cpumask_populate() Kumar Kartikeya Dwivedi 2026-07-11 23:38 ` Tejun Heo 2026-07-11 0:00 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox