[PATCH bpf-next v7 0/2] bpf, arena: fix range_tree consistency on allocation failure

chenyuan_fl@163.com posted 2 patches 1 day, 4 hours ago
kernel/bpf/range_tree.c | 52 ++++++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 22 deletions(-)
[PATCH bpf-next v7 0/2] bpf, arena: fix range_tree consistency on allocation failure
Posted by chenyuan_fl@163.com 1 day, 4 hours ago
From: Yuan Chen <chenyuan@kylinos.cn>

The arena range tree can be left inconsistent when kmalloc_nolock()
fails mid-operation. Patch 1 fixes range_tree_clear(), patch 2 fixes
range_tree_set().

Thanks for the review.

Changes in v7:
  - Dropped the third patch (checking range_tree_set() return in
    arena_free_pages/arena_free_worker) per Alexei Starovoitov: a range
    that stays marked allocated while its pages were freed is the same
    state bpf_arena_reserve_pages() creates, and nothing relies on an
    allocated range having pages. The failed free only costs page_cnt
    pages of address space, while aborting the free would leak pages
    the prog cannot observe or retry. No separate series for
    arena_vm_fault() either.
  - range_tree_set(): do the adjacency lookup once, before the clear,
    and drop the unreachable -EFAULT checks, per Alexei Starovoitov.

Changes in v6:
  - Patch 3 only: on a failed range_tree_set() drop the span and leak the
    range, which keeps the range tree and the page tables consistent, and
    revert the arena_map_free() teardown changes that went with the
    retry. Patches 1 and 2 are unchanged from v5.

Changes in v5:
  - arena_map_free(): set a dying flag and steal orphaned spans before
    draining, and drain with flush_work() + irq_work_sync() +
    flush_work().  The worker retry queues arena->free_irq, which the
    old irq_work_sync() + flush_work() order could miss: the irq_work
    fired after the arena was freed and its callback scheduled
    free_work on freed memory.
  - arena_map_free(): retry the spinlock acquisition a bounded number
    of times (-EDEADLK is not retried) and WARN with the error code,
    instead of a bare WARN_ON_ONCE(1) and an immediate leak of the
    arena.
  - range_tree_set(): reword the comment describing the two lookups,
    as suggested by Alexei Starovoitov.  The pre-clear probe only
    decides whether a fresh node must be allocated, so that -ENOMEM
    leaves the tree unmodified; the post-clear lookup fetches the
    merge handles without depending on how range_tree_clear()
    truncates overlapping nodes.

Changes in v4:
  - arena_free_worker(): keep a span whose range_tree_set() failed on
    arena->free_spans and retry it on a later worker run, instead of
    leaving it in the drained list where the second loop would still
    zap user VMAs and free the span (dropping the free request), as
    pointed out by Emil Tsalapatis.

Changes in v3:
  - Check range_tree_set() return value in arena_alloc_pages()'s error
    path, which restores the unpopulated tail of a partially allocated
    range (previously ignored), as pointed out in review.

Changes in v2:
  - Fix multi-line comment style in patches 1 and 3 (opening /* on its
    own line), as pointed out in review.

Yuan Chen (2):
  bpf, arena: fix range_tree_clear inconsistency on kmalloc_nolock
    failure
  bpf, arena: fix range_tree_set inconsistency on kmalloc_nolock failure

 kernel/bpf/range_tree.c | 52 ++++++++++++++++++++++++++++---------------------
 1 file changed, 30 insertions(+), 22 deletions(-)

-- 
2.54.0