mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
Merge branch 'bpf-require-an-owned-cpumask-for-bpf_cpumask_populate'
Nicholas Dudar says: ==================== bpf: require an owned cpumask for bpf_cpumask_populate() 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. ==================== Link: https://patch.msgid.link/20260709182800.2037938-1-main.kalliope@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
commit
25935519f7
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) ? \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user