diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2026-06-09 21:23:12 -0700 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-06-09 21:23:12 -0700 |
| commit | 1fed2e47fac582e824f77f68722a8a13820e58e2 (patch) | |
| tree | 703f21d578314c1ee115b1c9a44ee754bdbd90cf /include | |
| parent | 140fa23df957b51385aa847986d44ad7f59b0563 (diff) | |
| parent | 2e7c6cb4d8437a2fe7cd95aac7ca53d7eb05e9f4 (diff) | |
Merge branch 'fix-kptr-dtor-deadlock'
Kumar Kartikeya Dwivedi says:
====================
Fix kptr dtor deadlock
Referenced kptr destruction can run from tracing/NMI contexts through
bpf_obj_drop() and map value update/delete paths, reaching NMI-unsafe
special field teardown and deadlocks. Justin reported the issue and
iterated on fixes in [0]-[2], and also confirmed the bpf_obj_drop()
reproducer in [3].
This series rejects unsafe obj drops from non-iterator tracing programs,
limits map value recycle to NMI-safe field cancellation, and adds
focused selftests for the obj_drop(), NMI delete, and recycle teardown
cases.
See patches for details.
[0]: https://lore.kernel.org/bpf/20260505150851.3090688-1-utilityemal77@gmail.com
[1]: https://lore.kernel.org/bpf/20260507175453.1140400-1-utilityemal77@gmail.com
[2]: https://lore.kernel.org/bpf/20260519011450.1144935-1-utilityemal77@gmail.com
[3]: https://lore.kernel.org/bpf/agyG3eQwgmoJwmj2@suesslenovo
Changelog:
----------
v2 -> v3
v2: https://lore.kernel.org/bpf/20260609093719.2858096-1-memxor@gmail.com
* Replace bpf_obj_cancel_fields() to use bpf_map_free_internal_structs(). (Mykyta)
* Fix CI failures.
v1 -> v2
v1: https://lore.kernel.org/bpf/20260608144841.1732406-1-memxor@gmail.com
* Drop is_tracing_prog_type() fix due to compat breakage, revisit separately.
* Rework bpf_obj_drop() fix to additionally reject non-iter tracing progs.
====================
Link: https://patch.msgid.link/20260609202548.3571690-1-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/bpf.h | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 62bba7a4876f..56f5da2b437f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -492,6 +492,35 @@ static inline bool btf_record_has_field(const struct btf_record *rec, enum btf_f return rec->field_mask & type; } +static inline bool btf_field_is_nmi_safe(enum btf_field_type type) +{ + switch (type) { + case BPF_SPIN_LOCK: + case BPF_RES_SPIN_LOCK: + case BPF_TIMER: + case BPF_WORKQUEUE: + case BPF_TASK_WORK: + case BPF_KPTR_UNREF: + case BPF_REFCOUNT: + return true; + default: + return false; + } +} + +static inline bool btf_record_has_nmi_unsafe_fields(const struct btf_record *rec) +{ + int i; + + if (IS_ERR_OR_NULL(rec)) + return false; + for (i = 0; i < rec->cnt; i++) { + if (!btf_field_is_nmi_safe(rec->fields[i].type)) + return true; + } + return false; +} + static inline void bpf_obj_init(const struct btf_record *rec, void *obj) { int i; @@ -2688,6 +2717,7 @@ bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *r void bpf_obj_free_timer(const struct btf_record *rec, void *obj); void bpf_obj_free_workqueue(const struct btf_record *rec, void *obj); void bpf_obj_free_task_work(const struct btf_record *rec, void *obj); +void bpf_obj_cancel_fields(struct bpf_map *map, void *obj); void bpf_obj_free_fields(const struct btf_record *rec, void *obj); void __bpf_obj_drop_impl(void *p, const struct btf_record *rec, bool percpu); |
