
Исследовательский репозиторий для CVE-2025-38502 — выход за границы в локальном хранилище cgroup BPF ядра Linux через хвостовые вызовы, позволяющий локальное повышение привилегий.

Abraxas Labs · abraxaslabs.tech · github.com/abraxas · @abraxas_null
Выход за границы доступа к локальному хранилищу cgroup BPF в ядре Linux через хвостовые вызовы
| CVE | CVE-2025-38502 |
| CWE | CWE-125 — чтение за границами буфера |
| Производитель | Ядро Linux |
| Компонент | kernel/bpf/core.c, include/linux/bpf.h (локальное хранилище cgroup + хвостовые вызовы) |
| Воздействие | Локальное повреждение памяти ядра; повышение привилегий возможно на неисправленных ядрах |
| Вектор атаки | Локальный (AV:L) |
| Привилегии | Низкие (PR:L) — процесс, способный загружать BPF-программы типа CGROUP_SKB (или эквивалентные программы, привязанные к cgroup) |
| Взаимодействие с пользователем | Отсутствует |
| CVSS 3.1 (kernel.org CNA) | 7.8 HIGH — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CVSS 3.1 (NVD) | 7.1 HIGH — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H |
| Публикация | 16 августа 2025 |
| Исправление в upstream | abad3d0 в 6.17-rc1; бэкпортировано в 6.16.1, 6.12.46, 6.6.105, 6.1.151, 5.15.192 |
Только для исследований / образовательных целей. Не запускайте, не разворачивайте и не используйте материалы из этого репозитория против любого хоста без явного письменного разрешения как от стороны, размещающей этот репозиторий, так и от владельца целевых систем. Обнаружено в дикой природе.
Имя исходного файла CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c обрезает идентификатор. Опубликованная запись — CVE-2025-38502. CVE Linux CVE-2025-3850 не существует.
Lonial сообщил, что локальное хранилище cgroup BPF может быть доступно за границами буфера при хвостовом вызове.
Верификатор eBPF проверяет типы каждой программы изолированно. Во время выполнения bpf_get_local_storage() не ищет карту текущей исполняемой программы. Он читает указатель на хранилище cgroup из current->bpf_ctx → bpf_cg_run_ctx → prog_item->cgroup_storage[]. Этот слот заполняется из изначально привязанной программы, а не из той, в которую был совершён хвостовой вызов.
Если программа A (малый размер значения BPF_MAP_TYPE_CGROUP_STORAGE) совершает хвостовой вызов программы B (большой размер значения), bpf_get_local_storage() программы B всё равно возвращает меньший буфер программы A. Обращения, разрешённые верификатором для карты B, выходят за конец выделенной памяти A.
Дефект был внесён в Linux 5.9 коммитом 7d9c342 (bpf: Make cgroup storages shared between programs on the same cgroup). Он был исправлен путём расширения bpf_map_owner массивом storage_cookie[], так что комбинации хвостовых вызовов принимаются только тогда, когда вызываемая программа использует те же карты хранилища cgroup, что и вызывающая, либо не использует их вовсе.
Это локальный выход за границы кучи ядра. Оценка серьёзности различается у разных производителей, поскольку они расходятся во мнении, является ли примитив «только чтением с DoS» или полным повреждением памяти:
| Источник | Оценка | Целостность | Примечания |
|---|---|---|---|
| kernel.org CNA / cve.org | 7.8 HIGH | Высокая | C:H/I:H/A:H — рассматривает ошибку как полное локальное воздействие |
| NVD | 7.1 HIGH | Отсутствует | C:H/I:N/A:H — конфиденциальность + доступность |
| Ubuntu | Средняя (7.1) | — | USN-7909 |
| Red Hat | 4.0 LOW | Отсутствует | C:N/I:N/A:L — оценено как ограниченная доступность |
| Amazon Linux | 4.0 Средняя | Отсутствует | тот же вектор, что и у Red Hat |
| SUSE | 6.1 Умеренная | Отсутствует | некоторые ветки SLE 15 помечены WONTFIX |
Что это означает на практике:
struct bpf_array, размещённый в том же slab/порядке) могут быть повреждены.map->ops, перехват хелпера, commit_creds / переключение пространства имён). Именно поэтому это дерево помечает проблему как LPE. Более низкая оценка Red Hat отражает их оценку для конкретного продукта, а не отсутствие ошибки.Ошибка не требует сетевого сервиса. Она локальная. Она не требует TTY, setuid-хелпера или взаимодействия с пользователем.
Две BPF-программы cgroup, каждая со своей BPF_MAP_TYPE_CGROUP_STORAGE (разделяемый вариант, BPF_CGROUP_STORAGE_SHARED):
| Программа | Роль | Размер значения хранилища |
|---|---|---|
| A | привязанная / вызывающая хвостовой вызов | малый (например, помещается в заданный порядок kmalloc) |
| B | цель хвостового вызова | большой (верификатор разрешает обращения до этого размера) |
Верификатор проверяет A относительно карты A, а B относительно карты B. Обе проходят.
Во время выполнения хелпер делает:
ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
storage = ctx->prog_item->cgroup_storage[stype];
if (stype == BPF_CGROUP_STORAGE_SHARED)
ptr = &READ_ONCE(storage->buf)->data[0];
else
ptr = this_cpu_ptr(storage->percpu_buf);
prog_item — это элемент массива для программы, запустившей выполнение cgroup, а не для программы, исполняемой в данный момент после bpf_tail_call. Таким образом, B работает с объектом хранилища A.
bpf_cgroup_storage_alloc() определяет размер резервного буфера из value_size карты. Буфер A слишком мал для проверенных обращений B. Результат — классическая путаница типов идентичности карты при передаче управления — то же семейство ошибок, что и другие проблемы BPF, когда «хелпер видит не ту карту, что верификатор».
Коммит 7d9c342 сделал хранилища cgroup разделяемыми между программами, привязанными к одной cgroup. Именно это разделение делает слот в контексте выполнения единым указателем, а не поиском по каждой программе, и поэтому ядра до 5.9 не затронуты.
BPF_PROG_TEST_RUN для программы BPF_PROG_TYPE_CGROUP_SKB выделяет хранилище cgroup на время теста. Это выделение располагается в куче ядра рядом с тем, что недавно было освобождено в том же классе размеров — включая карты struct bpf_array, чей value_size был выбран так, чтобы попасть в тот же порядок kmalloc. Поэтому выход за границы буфера хранилища может достичь полей bpf_map (ops, список RCU, value[]) соседней array-карты.