Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/linux/bpf_verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ struct bpf_reference_state {
* it matches on unlock.
*/
void *ptr;
bool forbid_sleep; /* ref prevents sleeping while held */
};

struct bpf_retval_range {
Expand Down Expand Up @@ -420,6 +421,7 @@ struct bpf_verifier_state {
u32 active_lock_id;
void *active_lock_ptr;
u32 active_rcu_locks;
u32 forbid_sleep_count;

bool speculative;
bool in_sleepable;
Expand Down
1 change: 1 addition & 0 deletions include/linux/btf.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#define KF_ARENA_ARG1 (1 << 14) /* kfunc takes an arena pointer as its first argument */
#define KF_ARENA_ARG2 (1 << 15) /* kfunc takes an arena pointer as its second argument */
#define KF_IMPLICIT_ARGS (1 << 16) /* kfunc has implicit arguments supplied by the verifier */
#define KF_FORBID_SLEEP (1 << 17) /* acquired reference forbids sleeping while held */

/*
* Tag marking a kernel function as a kfunc. This is meant to minimize the
Expand Down
3 changes: 2 additions & 1 deletion kernel/bpf/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4605,8 +4605,9 @@ BTF_ID_FLAGS(func, bpf_iter_num_new, KF_ITER_NEW)
BTF_ID_FLAGS(func, bpf_iter_num_next, KF_ITER_NEXT | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY)
BTF_ID_FLAGS(func, bpf_iter_task_vma_new, KF_ITER_NEW | KF_RCU)
BTF_ID_FLAGS(func, bpf_iter_task_vma_next, KF_ITER_NEXT | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_iter_task_vma_next, KF_ITER_NEXT | KF_RET_NULL | KF_ACQUIRE | KF_FORBID_SLEEP)
BTF_ID_FLAGS(func, bpf_iter_task_vma_destroy, KF_ITER_DESTROY)
BTF_ID_FLAGS(func, bpf_iter_task_vma_release, KF_RELEASE)
#ifdef CONFIG_CGROUPS
BTF_ID_FLAGS(func, bpf_iter_css_task_new, KF_ITER_NEW)
BTF_ID_FLAGS(func, bpf_iter_css_task_next, KF_ITER_NEXT | KF_RET_NULL)
Expand Down
44 changes: 33 additions & 11 deletions kernel/bpf/task_iter.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,8 @@ struct bpf_iter_task_vma_kern_data {
struct mm_struct *mm;
struct mmap_unlock_irq_work *work;
struct vma_iterator vmi;
u64 last_addr;
bool locked;
};

struct bpf_iter_task_vma {
Expand All @@ -819,7 +821,6 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
struct task_struct *task, u64 addr)
{
struct bpf_iter_task_vma_kern *kit = (void *)it;
bool irq_work_busy = false;
int err;

BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma));
Expand All @@ -840,14 +841,8 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
goto err_cleanup_iter;
}

/* kit->data->work == NULL is valid after bpf_mmap_unlock_get_irq_work */
irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work);
if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) {
err = -EBUSY;
goto err_cleanup_iter;
}

vma_iter_init(&kit->data->vmi, kit->data->mm, addr);
kit->data->locked = false;
kit->data->last_addr = addr;
return 0;

err_cleanup_iter:
Expand All @@ -862,18 +857,45 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
__bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it)
{
struct bpf_iter_task_vma_kern *kit = (void *)it;
struct vm_area_struct *vma;

if (!kit->data) /* bpf_iter_task_vma_new failed */
return NULL;
return vma_next(&kit->data->vmi);

if (!kit->data->locked) {
bool irq_work_busy;

irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work);
if (irq_work_busy || !mmap_read_trylock(kit->data->mm))
return NULL;

kit->data->locked = true;
vma_iter_init(&kit->data->vmi, kit->data->mm, kit->data->last_addr);
}

vma = vma_next(&kit->data->vmi);
if (vma)
kit->data->last_addr = vma->vm_end;
return vma;
}

__bpf_kfunc void bpf_iter_task_vma_release(struct bpf_iter_task_vma *it__iter)
{
struct bpf_iter_task_vma_kern *kit = (void *)it__iter;

if (kit->data && kit->data->locked) {
bpf_mmap_unlock_mm(kit->data->work, kit->data->mm);
kit->data->locked = false;
}
}

__bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it)
{
struct bpf_iter_task_vma_kern *kit = (void *)it;

if (kit->data) {
bpf_mmap_unlock_mm(kit->data->work, kit->data->mm);
if (kit->data->locked)
bpf_mmap_unlock_mm(kit->data->work, kit->data->mm);
put_task_struct(kit->data->task);
bpf_mem_free(&bpf_global_ma, kit->data);
}
Expand Down
Loading
Loading