Skip to content

Rule Format

Andrii Sheiko edited this page Nov 3, 2026 · 7 revisions

Rule Format

Builder нормалізує всі джерела (Data Sources) в один уніфікований формат рулсету. Завдяки цьому агент не знає і не мусить знати, звідки прийшло правило — з Canonical feed, OVAL чи Debian tracker.

Структура файлу

Кожен release-файл (focal.json, bookworm.json, …) має однакову обгортку:

{
  "version": "2026-05-13T19:24:59Z",
  "generated_at": "2026-05-13T19:24:59Z",
  "ttl": 3600,
  "rules": []
}

ttl (у секундах) керує кешем агента: поки кеш молодший за ttl, агент може використати його замість повторного завантаження; після — лише з явним --allow-expired-cache.

Структура правила

{
  "id": "CVE-2026-41205",
  "platform": "ubuntu",
  "release": "jammy",
  "check_type": "package_version",
  "operator": "lt",
  "value": "1.1.3+ds1-2ubuntu0.2",
  "code": 12345,
  "message": "Host package mako is vulnerable to CVE-2026-41205",
  "package_name": "mako",
  "severity": "medium",
  "references": [
    "https://www.cve.org/CVERecord?id=CVE-2026-41205"
  ],
  "source": "canonical-ubuntu-cves",
  "match_mode": "version",
  "rule_status": "fixed",
  "fixed_version": "1.1.3+ds1-2ubuntu0.2",
  "version_scheme": "deb",
  "updated_at": "2026-05-13T19:24:59Z"
}

Читається це правило так: «на Ubuntu jammy пакет mako версії, меншої за 1.1.3+ds1-2ubuntu0.2, вразливий до CVE-2026-41205; виправлення опубліковане саме в цій версії».

Типи перевірок

check_type Що порівнюється Де використовується
package_version Версія встановленого пакета (dpkg-query) проти value. На Ubuntu/Debian package_name — це source-пакет, див. нижче. Ubuntu і Debian — основна маса правил.
kernel_version Повна версія збірки запущеного ядра (/proc/version_signature) проти fixed_version; якщо її немає — ABI з uname -r проти value. Правило застосовується лише до треку (package_name), з якого зібране запущене ядро. Ubuntu path (Canonical feed, OVAL).
kernel_package_version Версія Debian-пакета, з якого зібране запущене ядро (uname -v); якщо її немає — версія встановленого пакета поточного ядра (linux-image-*). Debian path — Debian tracker веде kernel-фікси через source package linux, тому пряме порівняння з uname -r там ненадійне.

Для RPM-правил version_scheme = "rpm", а value/fixed_version містять повний EVR (epoch:version-release). Агент використовує RPM ordering замість dpkg --compare-versions. На AlmaLinux kernel rules порівнюють EVR RPM, якому належить /usr/lib/modules/<uname -r>, тому перевіряється саме запущене ядро, а не просто найновіший встановлений kernel package.

Запущене ядро (Ubuntu/Debian)

Агент перевіряє саме запущене ядро, а не встановлений пакет, бо після оновлення без перезавантаження вони розходяться:

  • Ubuntu, трек. OVAL і Canonical feed ведуть kernel-CVE окремо для кожного треку — source-пакета ядра (linux, linux-hwe-6.11, linux-lowlatency, linux-oracle...). Трек запущеного ядра — це ${source:Package} пакета linux-modules-$(uname -r) (запасний варіант — linux-image-unsigned-$(uname -r)). Signed-образи linux-image-* для цього не годяться: вони збираються з обгорток linux-signed*. Якщо жоден пакет не знайдено, трек вгадується з uname -r і таблиці GA-ядер. Виняток серед linux-* — linux-firmware: це прошивки пристроїв зі своєю версією на кшталт 20240318.git3b128b60-0ubuntu2.17, OVAL перевіряє їх як звичайний dpkg-пакет, тому builder робить для них package_version-правила, а не kernel-трек.
  • Ubuntu, версія. uname -r дає лише ABI (6.8.0-147-generic), а /proc/version_signature — повну версію збірки (Ubuntu 6.8.0-147.147-generic 6.8.12 → 6.8.0-147.147; файл друкує CONFIG_VERSION_SIGNATURE, вихідний код). Її агент порівнює з fixed_version за Debian ordering, тож ловить і виправлення в перезбірці з тим самим ABI (6.8.0-147.150).
  • Debian. Kernel team вшиває версію source-пакета в uname -v (#1 SMP PREEMPT_DYNAMIC Debian 6.12.96-1 (2026-07-20), змінна KBUILD_BUILD_VERSION_TIMESTAMP у debian/rules.real). Вона не змінюється при оновленні пакета на місці й лишається доступною, навіть якщо пакет запущеного ядра видалено.

З --kernel-version ці джерела ігноруються, бо описують запущене ядро, а не задане вручну.

Source- і binary-пакети (Ubuntu/Debian)

Canonical CVE feed, Ubuntu OVAL і Debian Security Tracker ведуть статуси й fixed versions по source-пакетах (glibc, openssl, openssh), а на хості встановлені binary-пакети, зібрані з них (libc6, libssl3, openssh-client). Тому агент читає з одного виклику dpkg-query також поля ${source:Package} і ${source:Version} (dpkg-query(1)) і матчить package_name так:

  1. якщо на хості є binary-пакети, зібрані з source-пакета package_name, порівнюється source-версія — саме в ній трекери публікують фікси, а версія binary може відрізнятися (binNMU-суфікс +bN, окремо версіоновані binary на кшталт bsdutils з util-linux);
  2. якщо з одного source встановлені binary різних версій, спершу порівнюється найновіша, а старіші перевіряються окремо (див. нижче);
  3. інакше package_name шукається як binary-пакет — як і раніше.

Для RPM (AlmaLinux OVAL) правила вже містять binary-імена, тож зіставляння із source-пакетами там немає.

Кілька встановлених версій

Старіша версія може лишатися поруч із новою з двох причин: це залишок, який не прибрали після оновлення, або вона справді ще використовується. Агент їх розрізняє:

  • RPM: кілька версій одного імені дають install-only пакети (kernel-devel) і перервані оновлення.
  • Ubuntu/Debian: dpkg тримає одну версію пакета на архітектуру, але binary-пакети одного source можуть мати різні версії: старий образ ядра, стара бібліотека після зміни назви, часткове оновлення.

Правила застосовуються так:

  1. Якщо вразлива найновіша версія — це звичайна знахідка.
  2. Якщо вразлива лише старіша, збіг позначається [leftover] за умови, що:
    • жоден її файл (rpm -ql / dpkg -L) не завантажений у процес згідно з /proc/*/maps;
    • на Ubuntu/Debian apt-cache policy не пропонує для її binary-пакетів новішої версії. Доступне оновлення означає часткове оновлення, а не залишок: такий пакет може запуститися будь-коли, навіть якщо зараз не працює.
  3. В усіх інших випадках це звичайна знахідка. Сюди входять запуск без root, бо процеси інших користувачів не видно, помилка rpm, dpkg чи apt-cache, а також файл, спільний для кількох версій.

[leftover] не приховує знахідку, але такі збіги йдуть у кінці списку й не підвищують exit code (Agent Reference). Advisory-правила й правила для запущеного ядра цю логіку не використовують.

Match modes

Кожне правило належить до одного з двох класів, і це головний поділ у форматі:

match_mode rule_status Значення
version fixed Опубліковано fixed version. Агент робить точне порівняння версій (operator + value) і дає precise-вердикт: хост або вже оновлений, або ще ні.
advisory vulnerable Вендор досі позначає пакет/реліз вразливим, точного порогу версії немає. Це сигнал, а не точна перевірка.
advisory pending Фікс відстежується, але fixed version ще не опублікована.

Практичні наслідки:

  • version-правила — це те, на що можна алертити впевнено: «встанови оновлення X».
  • advisory-правила показують незакриті CVE без опублікованого фіксу — корисно для видимості, але дія з боку адміністратора зазвичай неможлива, доки вендор не випустить фікс.
  • Прапорець агента --fixed-only відсікає advisory-збіги й лишає тільки precise-знахідки — типовий вибір для алертингу.

У advisory-правил fixed_version = null, а operator/value для матчингу не використовуються.

Clone this wiki locally