flawopen.com/Teardowns/cve-2024-26642-linux-nftables-anonymous-set-timeout
CVE-2024-26642: анонимное множество с флагом таймаута в nf_tables Linux
CVE-2024-26642 (CVSS 7.8 по оценке NIST): nf_tables_newset() принимала анонимные множества с флагом таймаута — сочетание, которое не создаёт ни один инструмент пространства пользователя, — и тем самым подвергала множества, привязанные к правилу, истечению элементов и сборке мусора. Linux 6.8 отклоняет его с -EOPNOTSUPP.
В гардеробе две системы. Номерные крючки принадлежат одному гостю на один вечер и освобождаются, как только он уходит. Талоны с временем каждый час обходит служащий и убирает всё просроченное. Бланк позволяет отметить обе галочки для одного пальто: крючок освобождается, когда гость уходит, и ещё раз — по графику служащего. Двое считают, что отвечают за один и тот же крючок, и никто не знает расписания другого. Исправление простое: бланк теперь не принимает эту пару галочек.
Ключевые понятия и термины
nf_tables set- Структура ядра с адресами, портами или другими ключами, с которыми сравнивают правила nftables; создаётся netlink-сообщением
NFT_MSG_NEWSETи обрабатываетсяnf_tables_newset(). Анонимное множество (NFT_SET_ANONYMOUS)- Безымянное множество вроде
{ 22, 80 }, записанное прямо в правиле. Оно привязано к этому единственному правилу и уничтожается вместе с ним в той же транзакции. NFT_SET_TIMEOUT- Флаг, задающий элементам множества срок жизни. Истёкшие элементы удаляет механизм сборки мусора множества.
NFT_SET_EVAL- Флаг для множеств, обновляемых из пути обработки пакетов; используется устаревшими инструкциями
meter. Исправление оставляет для них сочетание анонимное + таймаут + eval допустимым. CAP_NET_ADMIN в user namespace- nf_tables принимает настройку от любого процесса с CAP_NET_ADMIN в его сетевом namespace; непривилегированный пользователь получает это право, создав user namespace, если дистрибутив это разрешает.
Анализ первопричины
nf_tables_newset() в net/netfilter/nf_tables_api.c проверяла флаги множества только на неизвестные биты и конфликты MAP+OBJECT и EVAL+OBJECT. Она принимала NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT, поэтому множество, чья жизнь привязана к одному правилу и одной транзакции, могло ещё и иметь элементы с истекающим сроком, которые собирает сборщик мусора. Пространство пользователя такого сочетания не создаёт, и код управления временем жизни на него не рассчитан. Исправление в основной ветке отклоняет его с -EOPNOTSUPP, если не задан ещё и NFT_SET_EVAL. Публичные источники не описывают возникающую ошибку памяти подробно; NIST оценивает её в 7.8 (высокие конфиденциальность, целостность и доступность), CNA ядра — в 5.5 (только доступность).
Пошаговый сценарий атаки
Получить CAP_NET_ADMIN
Локальный пользователь создаёт user namespace и сетевой namespace (где разрешены непривилегированные user namespaces) и получает CAP_NET_ADMIN над состоянием nf_tables этого namespace.
Запросить недопустимое множество
В пакете netlink-сообщений процесс отправляет NFT_MSG_NEWSET с NFTA_SET_FLAGS = NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT и привязывает множество к новому правилу через выражение lookup.
Ядро соглашается
nf_tables_newset() не находит запрещённой пары флагов и создаёт привязанное к правилу анонимное множество, элементы которого имеют срок жизни.
Непроверенные пути времени жизни
Фиксация, откат или удаление правила теперь одновременно запускают разрушение множества и сборку мусора элементов — на путях, которые транзакционный код nf_tables не обрабатывает безопасно.
Исходный код: Уязвимый vs Защищённый вариант
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), before the fix */
if (nla[NFTA_SET_FLAGS] != NULL) {
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
(NFT_SET_MAP | NFT_SET_OBJECT))
return -EOPNOTSUPP;
if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
(NFT_SET_EVAL | NFT_SET_OBJECT))
return -EOPNOTSUPP;
/* BUG: NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT is accepted. A rule-bound
* anonymous set now also gets per-element expiry and garbage
* collection, a combination nft never creates and the set
* lifetime code was not written for. */
}
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), commit 16603605b667 */
if (nla[NFTA_SET_FLAGS] != NULL) {
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
(NFT_SET_MAP | NFT_SET_OBJECT))
return -EOPNOTSUPP;
if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
(NFT_SET_EVAL | NFT_SET_OBJECT))
return -EOPNOTSUPP;
/* FIX: anonymous sets are never used with timeouts from userspace,
* so reject the combination before the set exists. NFT_SET_EVAL
* stays allowed so legacy meters keep working. */
if ((flags & (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT | NFT_SET_EVAL)) ==
(NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT))
return -EOPNOTSUPP;
}
Чек-лист по защите системы для инженеров
- ✓Используйте ядро с коммитом 16603605b667 (Linux 6.8 или стабильное либо дистрибутивное ядро, в журнале изменений которого упомянута
CVE-2024-26642). - ✓Там, где нагрузкам они не нужны, отключите непривилегированные user namespaces (
kernel.в Debian и Ubuntu,unprivileged_userns_clone=0user.или ограничение userns через AppArmor в Ubuntu), чтобы локальные пользователи не добирались до nf_tables.max_user_namespaces=0 - ✓На хостах без nftables запретите загрузку модуля
nf_tables. - ✓В коде ядра и API описывайте допустимые сочетания флагов явным списком разрешённых и отклоняйте всё, что не создаёт ни один поддерживаемый клиент, а не только известные плохие пары.
- ✓Фаззите netlink-интерфейсы описаниями syzkaller, покрывающими каждый бит флагов, чтобы необычные сочетания сначала доходили до кода времени жизни объектов в тестах.