В вашем ядре сейчас есть баги, которые не найдут в течение многих лет. Я знаю это, потому что проанализировала 125 183 из них, каждая в 20-летней git-истории ядВ вашем ядре сейчас есть баги, которые не найдут в течение многих лет. Я знаю это, потому что проанализировала 125 183 из них, каждая в 20-летней git-истории яд

[Перевод] Физик проанализировала более 100 000 «исправленных» багов ядра Linux

2026/02/15 14:14
18м. чтение

В вашем ядре сейчас есть баги, которые не найдут в течение многих лет. Я знаю это, потому что проанализировала 125 183 из них, каждая в 20-летней git-истории ядра Linux помечена прослеживаемым тегом Fixes:.

Средний баг ядра существует 2,1 года. А некоторые подсистемы намного хуже: драйверы CAN‑шины [шины сети контроллеров] — в среднем 4,2 года, работа с сетью SCTP — 4,0 года. Самый долгоживущий баг в моём наборе данных — переполнение буфера в ethtool — сохранялся в ядре 20,7 лет. Подробно остановлюсь на утечке памяти из‑за подсчёта ссылок в netfilter, существовавшей 19 лет.

Я создала инструмент, который выявляет 92% исторических багов в отложенном тестовом наборе данных о времени коммита. Вот что я узнала.


Краткий обзор основных выводов

Цифры

Описание

125 183

Пары «исправления багов» с прослеживаемыми тегами Fixes:

123 696

Валидные записи после фильтрации (0 < время существования < 20,7 лет)

2,1 года

Среднее время до обнаружения бага

20,7 лет

Самый долгоживущий баг (переполнение буфера ethtool)

0% → 69%

Баги, найденные за 1 год (c 2010 по 2022 гг.)

92,2%

Полнота VulnBERT на отложенном тестовом наборе 2024 года

1,2%

Доля ложноположительных результатов (против 48% у чистой CodeBERT)

Первое открытие

Я начала с анализа последних 10 000 коммитов с тегом Fixes: в ядре Linux. После фильтрации невалидных ссылок (коммитов, указывающих на хеши за пределами репозитория, некорректных тегов или коммитов слияния) у меня осталось 9 876 валидных записей об уязвимостях. Для анализа времени существования я исключила 27 исправлений, сделанных в тот же день. Это баги, возникшие и исправленные в течение нескольких часов. Осталось 9 849 багов со значительным временем существования.

Результаты поразили меня:

Метрика

Значение

Проанализировано багов

9 876

Среднее время существования

2,8 года

Медианное время существования

1,0 года

Максимум

20,7 лет

Почти 20% багов скрывались 5 и более лет. Особенно плохо выглядела сетевая подсистема: в среднем по 5,1 года В netfilter я обнаружила утечку из-за счетчика ссылок, которая находилась в ядре 19 лет.

Первоначальное распределение багов по времени существования
Первоначальное распределение по времени существования (в годах)

Первоначальные результаты: половина ошибок обнаруживается в течение года, а 20% скрываются более пяти лет.

Но что-то меня беспокоило: мой набор данных содержал исправления только 2025 года. Видела ли я полную картину, или только верхушку айсберга?

Идём глубже: собираем всю историю

Я переписала свой майнер так, чтобы он находил каждый тег Fixes: с тех пор, как в 2005 году Linux перешел на Git. Шесть часов спустя у меня были 125 183 записи об уязвимостях, что в 12 раз больше, чем в первоначальном наборе.

Цифры существенно изменились:

Метрика

Только 2025

Полная история (2005–2025 гг.)

Проанализировано багов

9 876

125 183

Среднее время существования

2,8 года

2,1 года

Медианное время существования

1,0 года

0,7 года

Более 5 лет

19,4%

13,5%

10 и более лет

6,6%

4,2%

Полное распределение багов в наборе данных
Полное распределение багов по времени существования (в годах)

Полная история: 57% ошибок обнаружено в течение года. Длинный хвост меньше, чем кажется на первый взгляд.

Откуда такая разница? Мой первоначальный набор данных только за 2025 год был предвзят. Исправления в 2025 году содержат:

  • Новые баги, появившиеся и устранённые недавно.

  • Древние баги, наконец обнаруженные спустя много лет.

Древние баги искажали средний показатель вверх. Если включить полную историю всех багов, которые были обнаружены и исправлены за год, среднее время существования упадёт с 2,8 до 2,1 года.

Настоящая история: ускоряемся, но это сложно

Самый поразительный вывод из полного набора данных: баги, появившиеся в последние годы, исправляются гораздо быстрее.

Год появления

Баги

Среднее время существования

Процентов найдено за год

2010

1 033

9,9 лет

0%

2014

3 991

3,9 года

31%

2018

11 334

1,7 года

54%

2022

11 090

0,8 года

69%

На поиск багов, появившихся в 2010 году, ушло почти 10 лет. А появившиеся в 2024 году баги обнаруживаются за 5 месяцев. На первый взгляд выглядит как улучшение в 20 раз!

Но вот загвоздка: эти данные ограничены в правой части [временной шкалы]. Баги, появившиеся в 2022 году, не могут существовать 10 лет, ведь сейчас только 2026 год. В 2030 году мы можем обнаружить больше багов 2022 года, что повысит среднее значение.

Более справедливое сравнение — «Процентов найдено за год» и улучшение: с 0% 2010 г. до 69% 2022 г. Это реальный прогресс, вероятно, обусловленный:

  • Syzkaller, выпущенным в 2015-м.

  • Санитайзерами KASAN, KMSAN, KCSAN.

  • Лучшим статическим анализом.

  • Большим числом ревьюеров.

Но есть отставание. Когда я смотрю только на баги, исправленные в 2024–2025 годах:

  • 60% обнаружены за последние 2 года — это новые, быстро обнаруженные баги.

  • 18% появились 5–10 лет назад.

  • 6,5% появились более 10 лет назад.

Мы одновременно быстрее выявляем новые баги и медленно работаем над ~5400 древними багами, которые скрывались более 5 лет.

Методология

В ядре есть соглашение: когда коммит исправляет баг, он содержит тег Fixes:, указывающий на коммит, где баг возник.

commit de788b2e6227 Author: Florian Westphal <[email protected]> Date: Fri Aug 1 17:25:08 2025 +0200 netfilter: ctnetlink: fix refcount leak on table dump Fixes: d205dc40798d ("netfilter: ctnetlink: ...")

Я написала майнер, который:

  1. Запускает git log --grep="Fixes:", чтобы найти все коммиты-исправления.

  2. Извлекает хеш упомянутого коммита из тега Fixes:.

  3. Извлекает даты из обоих коммитов.

  4. Классифицирует подсистему по путям к файлам (более 70 выражений).

  5. Обнаруживает тип бага по ключевым словам в сообщении коммита.

  6. Рассчитывает время существования бага.

fixes_pattern = r'Fixes:\s*([0-9a-f]{12,40})' match = re.search(fixes_pattern, commit_message) if match: introducing_hash = match.group(1) lifetime_days = (fixing_date - introducing_date).days

Подробности о наборе данных:

Параметр

Значение

Версия ядра

v6.19-rc3

Дата сбора данных

6 января 2026 г.

Исправления, собранные с тех пор

16 апреля 2005 г. (эпоха git)

Всего записей

125 183

Уникальные коммиты исправлений

119 449

Уникальные авторы, которые ввели баг

9 159

С идентификатором CVE

158

Для стабильного бекпорта

27 875 (22%)

Примечание о покрытии. В ядре ~448 000 коммитов, где в той или иной форме есть слово fix, но только у ~124 000 (28%) правильно проставлен тег Fixes:. Мой набор данных отражает хорошо документированные баги, то есть баги, у которых мейнтейнеры выявили основную причину.

Баги варьируется от подсистемы

В некоторых подсистемах есть баги, которые сохраняются гораздо дольше, чем в других:

Подсистема

Количество багов

Среднее время существования

Драйверы/CAN

446

4,2 года

Сеть/SCTP

279

4,0 года

Сеть/IPV4

1,661

3,6 года

USB

2 505

3,5 года

TTY

1 033

3,5 года

netfilter

1 181

2,9 года

Сеть

6 079

2,9 года

Память

2 459

1,8 года

GPU

5 212

1,4 года

BPF

959

1,1 года

Время существоания багов в зависимости от подсистемы
Время существования багов в подсистемах, в годах. Топ-20, 100+ багов

Баги CAN-шины и SCTP сохраняются дольше всего. Баги BPF и GPU обнаруживаются быстрее всех.

Драйверы CAN-шины и сети SCTP имеют баги, которые сохраняются дольше всего, вероятно, потому, что оба — нишевые протоколы с меньшим охватом тестирования. Баги графического процессора (особенно Intel i915) и BPF обнаруживаются быстрее всех, вероятно, благодаря специальной инфраструктуре фаззинга.

Интересный вывод при сравнении истории только за 2025 год со всей историей:

Подсистема

Среднее, только 2025

Среднее, полная история

Разница

Сеть

5,2 года

2,9 года

-2,3 года

Файловая система

3,8 года

2,6 года

-1,2 года

Драйверы/Сеть

3,3 года

2,2 года

-1,1 года

GPU

1,4 года

1,4 года

0 лет

По данным только за 2025 год сеть выглядела ужасно (5,2 года!), но на самом деле она ближе к среднему значению за всю историю (2,9 года). Исправления 2025 года направлены на устранение накопившихся древних сетевых багов. В любом случае данные по GPU выглядят одинаково, и эти баги выявляются стабильно быстро.

Некоторые типы багов скрываются дольше других

Сложнее всего обнаружить состояние гонки. На обнаружение в среднем уходит 5,1 года:

Тип бага

Количество

Среднее время существования

Медианное время существования

Состояние гонки

1 188

5,1 года

2,6 года

Целочисленное переполнение

298

3,9 года

2,2 года

UAF [использование после освобождения]

2 963

3,2 года

1,4 года

Утечка памяти

2 846

3,1 года

1,4 года

Переполнение буфера

399

3,1 года

1,5 года

Подсчёт ссылок

2 209

2,8 года

1,3 года

Разыменовывание нулевого указателя

4 931

2,2 года

0,7 года

Взаимоблокировка

1 683

2,2 года

0,8 года

Почему состояния гонки так долго скрываются? Они недетерминированы и срабатывают только при определённых условиях во времени, которые могут возникать один раз на миллион выполнений. Даже такие санитайзеры, как KCSAN, могут отмечать только гонки, за которыми наблюдают.

30% багов исправляются их автором. Их исправляет человек, допустивший баг. Полагаю, владение кодом имеет значение.

Почему некоторые баги скрываются дольше

Меньше фаззинга. Syzkaller превосходно справляется с фаззингом системных вызовов, но затрудняется с протоколами, где отслеживается состояние. Фаззинг netfilter требует создания валидных последовательностей пакетов, которые проходят через специфичные состояния [в системе] отслеживания соединений.

Сложнее спровоцировать. Многие сетевые баги требуют:

  • Определённой последовательности пакетов.

  • Состояния гонки между конкурентными потоками.

  • Нехватки памяти во время табличных операций.

  • Особых топологий NUMA.

Старый код с меньшим числом наблюдателей. Основная сетевая инфраструктура, например nf_conntrack, написана в середине 2000-х. Она работает, поэтому никто не переписывает. Но «стабильность» означает, что меньше разработчиков активно проверяют код.

Практический пример. Баг 19 лет в ядре

Один из самых старых сетевых багов в моём наборе данных обнаружена в августе 2006 года и исправлена в августе 2025 года:

// ctnetlink_dump_table() - забагованный путь выполнения if (res < 0) { nf_conntrack_get(&ct->ct_general); // инкремент счётчика ссылок cb->args[1] = (unsigned long)ct; break; }

Ирония. Коммит d205dc40798d сам по себе был исправлением: «[NETFILTER]: ctnetlink: исправление взаимоблокировки при дампе таблицы». Патрик МакХарди исправлял тупик, удалив вызов _put(). При этом он допустил утечку из-за подсчёта ссылок, которая останется на 19 лет.

Баг: код не проверяет условие ct == last. Если текущая запись такая же, как уже сохранённая, то её счётчик ссылок увеличивается дважды, но только один раз уменьшается. Память никогда не освободится от объекта:

// Что должно проверяться: if (res < 0) { if (ct != last) // <-- эта проверка упускалась 19 лет nf_conntrack_get(&ct->ct_general); cb->args[1] = (unsigned long)ct; break; }

Последствия. Утечки памяти накапливаются. В конце концов nf_conntrack_cleanup_net_list() вечно ждёт, пока счётчик ссылок достигнет нуля. Удаление сетевого пространства имён зависает. Если вы используете контейнеры, это блокирует их очистку на неопределённый срок.

Почему баг существовал 19 лет? Вам приходилось из-за нехватки памяти запускать conntrack_resize.sh в цикле в течение ~20 минут? В коммите исправления сказано: «Это можно воспроизвести, запустив самотестирование conntrack_resize.sh в цикле. У меня это занимает ~20 минут на вытесняющем ядре». Никто не проводил конкретно эту последовательность испытаний в течение двух десятилетий.

Часто встречаются неполные исправления

Вот закономерность, которую я продолжаю наблюдать: кто-то замечает неопределённое поведение, отправляет исправление, но оно не закрывает дыру полностью.

Пример: проверка полей множества netfilter

Дата

Коммит

Что произошло

Январь 2020

f3a2181e16f1

Стефано Бривио добавил поддержку множеств с несколькими полями диапазона. Чтобы указать длину поля, вводит NFTA_SET_DESC_CONCAT.

Январь 2024

3ce67e3793f4

Пабло Нейра замечает, что код не проверяет, соответствует ли сумма длин полей общей длине ключа. Отправляет исправление. Сообщение коммита: «Я пока не спровоцировал падение из-за несовпадения длин полей и общей длины ключа для множества в nft_set_pipapo, но это UB [неопределённое поведение], которое необходимо запретить».

Январь 2025

1b9335a8000f

Исследователь безопасности находит обходной путь. Исправление 2024 года было неполным — всё ещё оставались пути кода, где могло быть несовпадение. Настоящее исправление отправлено.

Исправление 2024 года было признанием того, что что-то было не так, но Пабло не смог найти сбой, поэтому оно было консервативным. Год спустя кто-то нашел место падения.

Этот паттерн предполагает возможность обнаружить коммиты, где говорится нечто вроде this is undefined behavior [это неопределённое поведение] или I couldn't trigger this but... [Я не смог спровоцировать его, но…]. Эти фразы — флаги. Автор знает, что что-то не так, но не полностью описал баги. Такие баги заслуживают особой скрупулёзности.

Анатомия долгоживущего бага

Глядя на баги, существующие более 10 лет, я вижу общие закономерности:

1. Баги подсчёта ссылок

kref_get(&obj->ref); // ... путь с ошибкой возвращает [управление] без вызова kref_put()

Они не роняют систему сразу. Память утекает медленно. В долго работающей системе вы можете не заметить, пока несколько месяцев спустя убийца OOM [Out Of Memory — недостаточно памяти] не начнёт стрелять.

2. Отсутствие проверок на NULL после разыменования

struct foo *f = get_foo(); f->bar = 1; // сначала происходит разыменовывание if (!f) return -EINVAL; // проверка идёт позже

Компилятор может оптимизировать проверку NULL, поскольку вы уже разыменовали. Баги сохраняются, потому что на практике указатель редко имеет значение NULL.

3. Целочисленное переполнение при вычислении размера

size_t total = n_elements * element_size; // может переполниться buf = kmalloc(total, GFP_KERNEL); memcpy(buf, src, n_elements * element_size); // копирует больше, чем выделяет

Если n_elements поступает из пользовательского пространства, злоумышленник может вызвать выделение небольшого буфера, за которым следует большая копия.

4. Состояния гонки в конечных автоматах

spin_lock(&lock); if (state == READY) { spin_unlock(&lock); // здесь окно: другой поток может изменить состояние do_operation(); // предполагает, что состояние всё ещё READY }

Для состояния гонки требуется точный момент. Баги могут проявляться редкими сбоями, воспроизвести которые не сможет никто.

Возможно ли автоматически обнаружить эти баги?

Каждый день, когда в ядре появляется баг, — это ещё один день, когда миллионы устройств становятся уязвимыми. Смартфоны Android, серверы, встраиваемые системы, облачная инфраструктура — всё это работающий код ядра с багами, которые не будут найдены в течение многих лет.

Я создала VulnBERT. Эта модель прогнозирует, приведёт ли коммит к уязвимости.

Эволюция модели:

Модель

Полнота

FPR (доля ложноположительных срабатываний)

F1

Примечания

Случайный лес

76,8%

15,9%

0,80

Только созданные вручную признаки

CodeBERT (тонкая настройка)

89,2%

48,1%

0,65

Высокая полнота, бесполезная FPR

VulnBERT

92,2%

1,2%

0,95

Лучшее от обоих подходов

Проблема с чистой CodeBERT. Сначала я попробовала выполнить тонкую настройку CodeBERT напрямую. Результаты — 89% полноты, но 48% ложноположительных срабатываний (измерения проводились на том же тестовом наборе). Это бесполезно, отмечена половина всех коммитов.

Почему так плохо? CodeBERT изучает простое решение: «большая разница — опасно», «много указателей — рискованно». Эти корреляции существуют в обучающих данных, но не обобщаются. Модель сопоставляет поверхностным, а не настоящим паттернам багов.

Подход VulnBERT. Объединение распознавания нейронных паттернов с экспертизой в области знаний от человека.

┌───────────────────────────────────────────────────────────────────┐ │ ВХОД: Git Diff │ └───────────────────────────────┬───────────────────────────────────┘ │ ┌───────────────┴───────────────┐ ▼ ▼ ┌───────────────────────────┐ ┌───────────────────────────────────┐ │ Энкодер нарезанного diff │ │ Извлечение созданных признаков │ │ (CodeBERT + внимание) │ │ (51 ручной признак) │ └─────────────┬─────────────┘ └─────────────────┬─────────────────┘ │ [768 признаков] │ [51 признак] └───────────────┬───────────────────┘ ▼ ┌───────────────────────────────┐ │ Перекрёстное слияние │ │ "Когда код выглядит как X, │ │ признак Y становится весомее" │ └───────────────┬───────────────┘ ▼ ┌───────────────────────────────┐ │ Классификатор риска │ └───────────────────────────────┘

Основа производительности — эти нововведения:

1. Кодирование фрагментов для длинных различий. Ограничение CodeBERT в 512 токенов отсекает большинство различий ядра [в diff] (часто более 2000 токенов). Я разбиваю код на куски, кодирую каждый, а затем агрегирую при помощи обучаемого внимания:

# Обучаемое внимание к кускам diff chunk_attention = nn.Sequential( nn.Linear(hidden_size, hidden_size // 4), nn.Tanh(), nn.Linear(hidden_size // 4, 1) ) attention_weights = F.softmax(chunk_attention(chunk_embeddings), dim=1) pooled = (attention_weights * chunk_embeddings).sum(dim=1)

Модель изучает, какие фрагменты важны, например, со spin_lock, но без spin_unlock; это не бойлерплейт.

2. Объединение признаков за счёт перекрёстного внимания. Нейронные сети не учитывают паттерны, специфичные для области знаний. Я извлекаю 51 признак, созданный вручную, с помощью регулярных выражений и AST-подобного анализа различий:

Категория

Признаки

Базовые (4)

lines_added, lines_removed, files_changed, hunks_count

Память (3)

has_kmalloc, has_kfree, has_alloc_no_free

Подсчёт ссылок (5)

has_get, has_put, get_count, put_count, unbalanced_refcount

Блокировка (5)

has_lock, has_unlock, lock_count, unlock_count, unbalanced_lock

Указатели (4)

has_deref, deref_count, has_null_check, has_deref_no_null_check

Обработка ошибок (6)

has_goto, goto_count, has_error_return, has_error_label, error_return_count, has_early_return

Семантика (13)

var_after_loop, iterator_modified_in_loop, list_iteration, list_del_in_loop, has_container_of, has_cast, cast_count, sizeof_type, sizeof_ptr, has_arithmetic, has_shift, has_copy, copy_count

Структурные (11)

if_count, else_count, switch_count, case_count, loop_count, ternary_count, cyclomatic_complexity, max_nesting_depth, function_call_count, unique_functions_called, function_definitions

Ключевые признаки паттерна бага:

'unbalanced_refcount': 1, # kref_get без kref_put → утечка 'unbalanced_lock': 1, # spin_lock без spin_unlock → взаимоблокировка 'has_deref_no_null_check': 0,# *ptr без if(!ptr) → разыменование null 'has_alloc_no_free': 0, # kmalloc без kfree → утечка

Перекрёстное внимание изучает условные отношения. Когда CodeBERT видит паттерны блокировки и unbalanced_lock=1 — это высокий риск. Сигналов по отдельности недостаточно, значение имеет комбинация.

# Слияние признаков через перекрёстное внимание feature_embedding = feature_projection(handcrafted_features) # 51 → 768 attended, _ = cross_attention( query=code_embedding, # Какие паттерны есть в коде? key=feature_embedding, # Что говорят созданные вручную признаки? value=feature_embedding ) fused = fusion_layer(torch.cat([code_embedding, attended], dim=-1))

3. Потеря фокуса в сложных паттернах. Обучающие данные несбалансированы там, где большинство коммитов безопасно. Стандартные обновления градиента кросс-энтропии на простых примерах. Очаговая потеря:

Standard loss when p=0.95 (easy): 0.05 Focal loss when p=0.95: 0.000125 (400x smaller)

Модель фокусируется на неоднозначных коммитах: «жёстких», важных пяти процентах.

Влияние каждого компонента (оценивается на основе экспериментов с абляцией):

Компонент

Оценка F1

Базовый уровень CodeBERT

~76%

+ Очаговая потеря

~80%

+ Слияние признаков

~88%

+ Контрастное обучение

~91%

Вся VulnBERT

95,4%

Ключевой вывод: ни нейронные сети, ни созданные вручную правила не достигают наилучших результатов сами по себе. Комбинация — да.

Результаты временной проверки (обучающий набор — ≤ 2023, тестовый — 2024):

Метрика

Цель

Результат

Полнота

90%

92,2%

FPR

<10%

1,2%

Точность

98,7%

F1

95.4%

AUC

98,4%

Что означают эти показатели:

  • Полнота 92,2%. Из всех коммитов, вызывающих баги, обнаруживается 92,2%. Отсутствует 7,8% багов.

  • FPR 1,2%. Из всех безопасных коммитов некорректно отмечаются 1,2%. Ниже FPR = меньше ложных срабатываний.

  • Точность 98,7%. Из коммитов, которые отмечаются как рискованные, на самом деле таковыми являются 98,7%. Модель почти всегда права, когда поднимает тревогу.

  • F1 95,4%. Гармоническое среднее значение точности и полноты. Одно число, суммирующее общую производительность.

  • AUC 98,4%. Площадь под кривой ROC. Измеряет качество ранжирования — насколько хорошо модель отделяет баги от безопасных коммитов по всем пороговым значениям.

Модель правильно различает один и тот же баг на разных стадиях:

Коммит

Описание

Риск

acf44a2361b8

Исправление UAF в xe_vfio

12,4% LOW

1f5556ec8b9e

Введено UAF

83,8% HIGH

Что видит модель? 19-летний баг

При анализе коммита, содержащего баг d205dc40798d:

- if (ct == last) { - nf_conntrack_put(&last->ct_general); // удалено! - } + if (ct == last) { + last = NULL; continue; } if (ctnetlink_fill_info(...) < 0) { nf_conntrack_get(&ct->ct_general); // ещё здесь

Извлечённые признаки:

Признак

Значение

Сигнал

get_count

1

Есть nf_conntrack_get()

put_count

0

Удалена nf_conntrack_put()

unbalanced_refcount

1

Обнаруженные несоответствия

has_lock

1

Использует read_lock_bh()

list_iteration

1

Использует list_for_each_prev()

Прогноз модели: 72% риска: HIGH.

Признак unbalanced_refcount активируется, поскольку put() удалена, но get() осталась. Классический паттерн утечки из-за подсчёта ссылок.

Ограничения

Ограничения набора данных:

  • Только баги с тегами Fixes: (~28% коммитов исправлений). Предвзятость отбора: хорошо документированные баги, как правило, более серьёзны.

  • Только ветка main: не содержит исправления только для стабильных веток и исправления вендоров.

  • Эвристическая классификация подсистем (регулярное выражение по файловым путям).

  • Обнаружение типа бага по соответствию ключевых слов в сообщениях коммита, многие баги относятся к типу неизвестных.

  • При расчёте времени существования учитываются даты авторов ошибки, а не даты коммитов, перебазирование может искажать временные метки.

  • Некоторые «баги» могут быть теоретическими (комментарии типа fix possible race [исправить возможную гонку] без подтверждённого триггера).

Ограничения модели:

  • 92,2% полноты приходится на отложенный тестовый набор 2024 года, что не гарантия для будущих багов.

  • Нельзя обнаружить семантические баги (баги логики без синтаксического сигнала).

  • Межфункциональные «слепые зоны» (баг охватывает несколько файлов).

  • Смещение обучающих данных (паттерны изучаются по найденным багам, новые могут быть пропущены).

  • Ложные срабатывания из-за намеренного поведения (инициализация/очистка в разных коммитах).

  • Протестировано только на коде ядра Linux, не может распространяться на другие кодовые базы.

Статистические ограничения:

  • Смещение времени существования багов при сравнении по годам (недавние баги пока не могут существовать долго).

  • Корреляция ≠ причинно‑следственная связь для различий подсистемы/типа бага.

Что это означает: VulnBERT — это инструмент сортировки, а не гарантия. Она обнаруживает 92% багов с узнаваемыми закономерностями. Остальные 8% и новые классы ошибок все ещё нуждаются в человеческом анализе и фаззинге.

Что дальше

Полнота 92,2% и FPR 1,2% готовы к работе в продакшене. Но есть ещё кое‑что, что нужно сделать:

  • Исследование на основе RL. Вместо статического сопоставления с образцом научите агента исследовать пути кода и самостоятельно находить баги. Текущая модель прогнозирует риск; агент RL cможет генерировать триггерные входные данные.

  • Интеграция Syzkaller. Сделать покрытие фаззера сигналом вознаграждения. Если модель отмечает коммит и Syzkaller обнаруживает сбой в данном пути кода, это сильный положительный сигнал.

  • Модели, специфичные для подсистемы. Сетевые баги имеют иные закономерности, чем баги драйверов. Модель, настроенная на netfilter, на коммитах netfilter может превзойти общую.

Цель не в том, чтобы заменить ревьюеров, а в том, чтобы указать на 10% коммитов, которые, скорее всего, будут проблематичны, чтобы люди могли сосредоточить внимание там, где это важно.

Воспроизведение

При извлечении набора данных применяется соглашение о тегах ядра Fixes:.

Вот основная логика:

def extract_fixes_tag(commit_msg: str) -> Optional[str]: """Извлекает ID коммита из тега Fixes:""" pattern = r'Fixes:\s*([a-f0-9]{12,40})' match = re.search(pattern, commit_msg, re.IGNORECASE) return match.group(1) if match else None # Майнит все теги Fixes: из истории git git log --since="2005-04-16" --grep="Fixes:" --format="%H" # Для каждого коммита исправления: # - Извлекает хеш коммита, где баг введён # - Берёт даты обоих коммитов # - Вычисляет время существования # - Классифицирует подсистему по путям к файлам

Полный код майнера и набор данных: github.com/quguanni/kernel-vuln-data.


TL;DR

  • 125 183 бага проанализировано в 20-летней истории ядра Linux в git (123 696 с валидным временем существования).

  • Средний срок существования бага: 2,1 года (2,8 года по данным только за 2025 год из‑за систематического сдвига времени существования в недавних исправлениях).

  • 0% → 69% багов, обнаруженных в течение 1 года (2010–2022 гг.). Это реальный прогресс за счёт лучших инструментов.

  • 13,5% багов скрываются более 5 лет. Это самые опасные баги.

  • Дольше всего скрываются состояния гонки (в среднем 5,1 года).

  • VulnBERT обнаруживает 92,2% багов в отложенном тестовом наборе 2024 года с FPR всего 1,2% (98,4% AUC).

  • Набор данных: github.com/quguanni/kernel-vuln-data.


Если вы работаете над безопасностью ядра, обнаружением уязвимостей или машинным обучением для анализа кода, мне бы хотелось поговорить: [email protected].

Источник

Возможности рынка
Логотип Ucan fix life in1day
Ucan fix life in1day Курс (1)
$0.0006297
$0.0006297$0.0006297
-0.67%
USD
График цены Ucan fix life in1day (1) в реальном времени
Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу service@support.mexc.com для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.

Вам также может быть интересно

Аналитики оценили потенциал биткоина после возвращения к $70 000

Аналитики оценили потенциал биткоина после возвращения к $70 000

На графике первой криптовалюты сформировался бычий паттерн «Адам и Ева» — прорыв выше $72 000 подтолкнет актив к $80 000. На это обратил внимание аналитик под п
Поделиться
ProBlockChain2026/02/15 16:50
Следующая криптовалюта, которая взорвется в феврале 2026 года: Aptos борется с зоной перепроданности, Dogecoin застыл на месте, а предпродажа DeepSnitch AI стремительно движется к неизбежному запуску с ростом в 1000 раз

Следующая криптовалюта, которая взорвется в феврале 2026 года: Aptos борется с зоной перепроданности, Dogecoin застыл на месте, а предпродажа DeepSnitch AI стремительно движется к неизбежному запуску с ростом в 1000 раз

Даже Coinbase, крупнейшая криптобиржа США, только что зафиксировала чистый убыток в размере 667 млн $ в 4 квартале 2025 года. Это первый убыточный квартал за два года на фоне обвала криптовалютных рынков
Поделиться
Blockonomi2026/02/15 20:02
Акции Coinbase взлетели после отчета о прибыли: вот почему рост может быть недолгим

Акции Coinbase взлетели после отчета о прибыли: вот почему рост может быть недолгим

Ключевые выводы: акции Coinbase выросли более чем на 17% в пятницу. Bitcoin и другие криптовалюты восстановились одновременно. Рост последовал за публикацией компании
Поделиться
Themarketperiodical2026/02/15 20:44