LINUX.ORG.RU

Уязвимость в ядре Linux с возможностью локальной эксплуатации через nftables

 , ,


0

3

Обнаружена уязвимость в подсистеме Netfilter (CVE-2023-6817), которая, в теории, может быть использована локальным пользователем для повышения своих привилегий в системе. Корень проблемы кроется в использовании освобожденной памяти (use-after-free) в модуле nf_tables, ответственном за функциональность пакетного фильтра nftables.

Уязвимость актуальна с версии ядра Linux 5.6. Исправление предложено в тестовом выпуске ядра Linux 6.7-rc5 и внесено в текущие стабильные ветки 5.10.204, 5.15.143, 6.1.68 и 6.6.7.

Проблема вызвана ошибкой в функции nft_pipapo_walk, которая не проводит проверку наличия дубликатов в процессе перебора элементов PIPAPO (Pile Packet Policies). Это приводит к двойному освобождению памяти. Для успешной атаки требуется доступ к nftables, который можно получить, обладая правами CAP_NET_ADMIN в любом пространстве имен пользователя (user namespace) или сетевом пространстве имен (network namespace). Эти права могут быть предоставлены, например, в изолированных контейнерах. Для проверки своих систем опубликован прототип эксплоита.

>>> Подробности



Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 1)

Ответ на: комментарий от hateWin

Прикол в том, что даже unsafe в расте – это не сишный ад и холокост

Это наглая ложь, и это уже обсуждалось очень много раз.

Rust всемогущий: ищу истории успеха (комментарий)

Rust всемогущий: ищу истории успеха (комментарий)

“Unsafe Rust is hard. A lot harder than C, this is because unsafe Rust has a lot of nuanced rules about undefined behaviour (UB) — thanks to the borrow checker — that make it easy to perniciously break things and introduce bugs.”

shdown
()
Ответ на: комментарий от ergo

при том, что CAP_SYS_ADMIN просто так без контейнера не появится. Уже задолбался видеть посты УУУ ОПЯТЬ УЯЗВИМОСТЬ В ЯДРЕ, а потом оказывается что это уязвимость требует чуть ли не локального рута, пускай даже в контейнере. Однако, если мне надо будет запустить недоверенный софт, то CAP_SYS_ADMIN у него даже в контейнере, очевидно, не будет, а если понадобится - добро пожаловать в KVM. Кстати, у всех _нормальных_ хостеров KVM давно, а контейнеры используются равзе что внутри виртуалок для всяких докеров, где цель - не изоляция, а обеспечение нужных рантаймов (по сути хватило бы chroot, но чтобы упростить настройку сети тут и сеть в неймспейсе)

mittorn ★★★★★
()
Ответ на: комментарий от hateWin

По ссылке какое-то «ололо пук среньк»

Нет, по ссылкам обсуждение:

  1. Вот этого текста: https://zackoverflow.dev/writing/unsafe-rust-vs-zig/

Unsafe Rust is hard. A lot harder than C, this is because unsafe Rust has a lot of nuanced rules about undefined behaviour (UB) — thanks to the borrow checker — that make it easy to perniciously break things and introduce bugs.

This is because the compiler makes optimizations assuming you’re following its ownership rules. But if you break them, thats considered undefined behaviour, and the compiler chugs along, applying those same optimizations and potentially transforming your code into something dangerous.

To make matters worse, Rust doesn’t fully know what behaviour is considered undefined4, so you could be writing code that exhibits undefined behaviour without even knowing it.

  1. Вот этого документа: https://doc.rust-lang.org/reference/behavior-considered-undefined.html

Warning: The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust’s semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe.

Если для тебя это «ололо пук среньк», то ты просто-напросто сектант, который затыкает ушли и говорит «ла-ла-ла, я ничего не слышу», когда ему указывают на несостоятельность его веры.

Вот что написано в официальной документации Сравни с сишечкой

Там приведён список того, что делать нельзя, причём правила эти сложнее и менее очевидны, чем в Си. Что именно я должен сравнить с сишечкой?

При том, что конструкции unsafe Rust просто компилируются в соответствующие инструкции LLVM IR (например, получение значения по указателю → load), у которого список undefined behavior скопирован с Си.

shdown
()
Ответ на: комментарий от shdown

Половина пишущих про раст, нихера в этом самом расте не понимают и выводят хрен пойми что из того, что о чём по поводу(и иногда без) ноет оставшаяся половина.

да, делать прослойку unsafe кода, который взаимодействует с железом очень больно. Это считай как писать на си но в синтаксисе раста. Но эта прослойка относительно всего остального кода довольно тонкая, а главное отделена видимым заборчиком. А в остальных местах компилятор тебе по рукам батареей кидается там, где сишный компилятор скажет «ну ок, ссзб, чо».

Dark_SavanT ★★★★★
()
Ответ на: комментарий от shdown

Unsafe Rust is hard

Это просто словоблудие. Открой официальную документацию и посмотри, что разрешено внутри unsafe. Срать в память за пределами массива там не разрешается.

hateWin ★☆
()
Ответ на: комментарий от shdown

Вот этого документа: https://doc.rust-lang.org/reference/behavior-considered-undefined.html

Ну и найди мне там out-of-boundary acces или доступ к уже освобожденной вручную памяти. Это типичные уязвимости в сишке.

Никто не говорит, что раст – серебрянная пуля. Этот бред придумали упоротые фанатики сишки, чтобы потом с умным видом опровергать.

hateWin ★☆
()
Ответ на: комментарий от hateWin

Ты вообще осилил прочитать полностью хотя бы ту часть, которую я процитировал? Тезис того человека не в том, что unsafe Rust is hard потому, что там можно испортить память. А потому, что в unsafe Rust есть множество сложных/неочевидных/тонких правил касательно неопределённого поведения — из-за borrow checker — благодаря которым становится очень легко губительным образом поломать вещи и привнести баги.

shdown
()
Ответ на: комментарий от shdown

unsafe Rust есть множество сложных/неочевидных/тонких правил касательно неопределённого поведения — из-за borrow checker — благодаря которым становится очень легко губительным образом поломать вещи и привнести баги.

Ты повторяешь одно и тоже. Я говорю, что даже при использовании unsafe раст безопасней Си. От тебя только и слышно «ололо вы все врёти». Давай ты найдешь высказывание разработчиков раста, из которого следует, что внутри unsafe раст позволяет срать в память мимо массива. Или писать в уже освобожденную память.

hateWin ★☆
()
Последнее исправление: hateWin (всего исправлений: 1)
Ответ на: комментарий от hateWin

Ну и найди мне там out-of-boundary acces или доступ к уже освобожденной вручную памяти. Это типичные уязвимости в сишке.

Доступ к уже освобожденной памяти перечислен во втором пункте этого документа:

Evaluating a dereference expression (*expr) on a raw pointer that is dangling or unaligned, even in place expression context (e.g. addr_of!(*expr)).

Out-of-boundary access, очевидно, тоже является undefined behavior. Даже само получение указателя на фиг-знает-что (за пределами валидного объекта в памяти) им является (https://doc.rust-lang.org/std/primitive.pointer.html#method.offset):

If any of the following conditions are violated, the result is Undefined Behavior:

  • Both the starting and resulting pointer must be either in bounds or one byte past the end of the same allocated object.
  • The computed offset, in bytes, cannot overflow an isize.
  • The offset being in bounds cannot rely on “wrapping around” the address space. That is, the infinite-precision sum, in bytes must fit in a usize.
shdown
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от hateWin

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

Тебе нужно именно высказывание разработчиков раста, или достаточно будет наглядно продемонстрировать этот факт?

Факт могу продемонстрировать: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a5ce718c658535ac4887d4e1c9167821

shdown
()
Ответ на: комментарий от hateWin

Берёшь число, приводишь к адресу, разыменовываешь, пишешь. Профит.

Другое дело, что если ты так делаешь, то это обычно очень низкоуровневый код и там обычно люди знают что делают.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от hateWin

То же самое с «писать в уже освобожденную память»: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=51be1690b42a9929bdf6c9ba854e02c9

Я говорю, что даже при использовании unsafe раст безопасней Си. От тебя только и слышно «ололо вы все врёти».

Почему безопасней? По каким причинам? По каким причинам небезопасней, я написал.

shdown
()
Ответ на: комментарий от Dark_SavanT

без арифметики указателей?

Для начала определи, что это такое. Можно и просто число в указатель кастануть, например, никакой арифметики нет, а out-of-bounds указатель теперь есть.

shdown
()
Ответ на: комментарий от xwicked

Погодите. Получается, что это простой юзверь с ограниченной учёткой может, используя уязвимость, поднять права до рута и слить данные фирмы или обрушить одинэс, например? Или ученик сможет получить права учителя и накачать игорей?
Тогда, блин, да - это огромная дырище в безопасности...

xwicked ★★☆
()
Ответ на: комментарий от ergo

Контейнеры особенные вот чем: если ты даёшь кому-то рут доступ с правами настройки файрволла на хосте - то этот юзер скорее всего админ и в любом случае может делать с системой что захочет. Если же ты кому-то дал доступ к настройке файрволла в контейнере, то это всего лишь клиент твоего хостинга с расширенными возможностями настройки, и возможность влиять на всю систему в целом, которую даёт этот баг, там совсем не запланирована.

firkax ★★★★★
()
Ответ на: комментарий от gns

Как ни пиши, но когда у тебя выделенная память под указателем через полядра тащится и освобождается в неочевидном месте, то double free будут всегда

Да вот нет. Необходимые дополнительные условия - нубопрограммисты и отсутствие внятного контракта на взаимодействие между частями ядра (хотя бы модулями, а лучше всеми не-static функциями).

firkax ★★★★★
()
Ответ на: комментарий от dimgel

Причина, полагаю, в том, что C++ сильно злее в плане контроля типов, и поэтому у его оптимизатора больше информации.

Это стоит перефразировать: С++ делает заметно больше допущений касательно того, чего НЕ будет делать код, что позволяет конечно больше оптимизировать, но с другой - это больше UB и меньше гибкости в руках программиста. Гибкость программирования важнее, а чтоб не страдать от недооптимизаций - надо сразу писать оптимизированный код, а не надеяться на компилятор.

firkax ★★★★★
()
Ответ на: комментарий от gns

Поэтому, зачем тянут раст для меня не есть пока понятно.

Для маркетинга в сфере поиска работников. Это единственная причина. Программисты на Си, которые писали ядро, со временем устали и плавно расходятся, новые в этот бардак лезть не хотят - вот и ищут среди более доступных и сговорчивых.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Лучше бы денег вложили в документальное сопровождение новых версий. Основная проблема не висящие ссылки, а неизвестность. Смотришь в код, и тебе не всегда понятно, что он делает, зачем он написан, и что на самом деле хотел сказать автор. Как бы, алгоритмы или концепции описывать надо. Документация есть, конечно, и bootlin сильно помогает, но все таки...

gns ★★★★★
()
Ответ на: комментарий от firkax

Эк Вы, батенька, чего захотели.... Внятного контракта!! :) Я двумя руками за. При внятном контракте хоть на чем пиши. :) Но это из области благопожеланий. При внятном контракте на взаимодействие существующего нужен еще и внятный контракт на дальнейшее развитие... Дальше продолжать?

gns ★★★★★
()
Ответ на: комментарий от hateWin

Ну это значит, что кроме написанного кода, в расте есть еще скрытая исполняющая система типа «конвой с автоматом»: «тут ходи, а тут не ходи». Я не знаю, как это будет работать в ядре при блокировках, rcu-локах и прочем всем. Называется «а давайте затащим в ядро исключения». На ваще атлична, например! :)

gns ★★★★★
()

а что вам знакомо об уязвимостях «нулевого дня» в опенсорсных ядрах/systemd?) или из нас так много кто бы крутился на «белое» ойти и занимался днями напролёт тем как дебажил ядра и шлёпал по жеппе поборников пропритетарщины 😶‍🌫️

loveFX
()
Ответ на: комментарий от dimgel

Не по указателю, а по ссылке. А если тащится туда, где её собираются освобождать, то move(unique_ptr). Семантика владения в плюсах вполне себе обложена достаточно простыми и интуитивными рекомендованными практиками

Практики плюсов, типа *ptr-ов, и прочее, вроде заведения объектов в контейнерах, это памперсы и прочие прокладки. Выглядит смешно, сильное мешает, и работает только если быстро и активно не двигаться, иначе все это разлетается с брызгами. На самом деле, использование указателей есть самый эффективный способ использования объектов и управления ими. Даже в гошку их притащили, потому что дюже удобно. Что касается проблем с ними, то нужно использовать тот же подход, что и в гошке: не заниматься извращениями вроде арифметики указателей, кастами совы к глобусу, и пилить в проекте свой аллокатор объектов. Не тот Alloc, что в stl-вских контейнерах, а глобальный на проект, типа своего специализированного GC, он будет специализированным и поэтому тормозов в системе не создаст. Многие крупные проекты на C++, возникшие до распространнения вон тех вон «простых и интуитивных рекомендованных практик», как раз такие аллокаторы в системе имеют, загляни, например, в Apache Traffic Server, посмотришь как там реализовано выделение объектов и их особождение. Дюже удобны указатели в ядре, а местами там иначе-то и нельзя. Иначе получится что-то тормознутое и неэффективное. Но да, сложно с ними.

slew
()
Последнее исправление: slew (всего исправлений: 1)
Ответ на: комментарий от slew

загляни, например, в Apache Traffic Server, посмотришь как там реализовано выделение объектов и их особождение

Ну первым делом увидел класс Arena – самую обыкновенную реализацию. Тоже мне фокус, у меня тоже такая есть. И в nginx есть request pool. Только всё на свете в арену не загонишь. И кроме того, семантика move – она не только и не столько про память.

Но меня больше позабавило, что ядрёный программист привёл в пример проект на C++: где же ваше с @firkax -ом единство?

dimgel ★★★★★
()
Последнее исправление: dimgel (всего исправлений: 2)
Ответ на: комментарий от dimgel

Ну первым делом увидел класс Arena – самую обыкновенную реализацию. Тоже мне фокус, у меня тоже такая есть.

Впрочем нет, у меня попроще. Невырожденный free() – это что-то новенькое, и вообще уже не арена. Но вникать лень.

dimgel ★★★★★
()
Ответ на: комментарий от dimgel

И кроме того, семантика move

move-один из костылей для возможности юзания объектов в контейнерах (помещение, перемещение), возможности передачи объектов не по указателю и прочее, существующее только при юзании «правильного С++». Чтоб оно не копировалось. Иначе придется копировать. В остальном оно не вперлось. Создал объект, используй объект, освобождай объект. В отдельных редких случаях когда оно нужно, не зазорно прикрутить swap метод объектам.

slew
()
Ответ на: комментарий от slew

В отдельных редких случаях когда оно нужно, не зазорно прикрутить swap метод объектам

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

Например, unique_ptr<какой-нить handle> вообще не умеет в копирование, а благодаря move-семантике его можно протаскивать где угодно, не боясь задвоений ссылок на handle и, соответственно, задвоенного close(). С нулевым оверхедом в рантайме (по сравнений с ручным пердолингом).

dimgel ★★★★★
()
Последнее исправление: dimgel (всего исправлений: 4)
Ответ на: комментарий от dimgel

С нулевым оверхедом в рантайме (по сравнений с ручным пердолингом).

Ну да, сначала придумали якобы удобство unique_ptr, а потом, чтоб это можно было использовать, навесили туда запреты копирования и мувинг only. Уже подпорки. Мувинг объектов нифига не без оверхеда. Там ряд операций который, попади оно в нагруженный участок кода, заметно отожрет такты процессора. Тупо передать указатель будет во много раз дешевле. Вообще, многие проблемы с указателями сильно преувеличены (явно намеренно), и являются или следствием других проблем, которые есть в любом ЯПб (ниже), или просто невнимательный разраб (а таких гнать). Например, use-after-free тот же, чаще всего это проблемы синхронизации. Когда один поток пытается поработать с объектом, который другой освободил. При наличии ошибок синхронизации может много каких приколов случиться, в любом ЯП. Просто в каждом ЯП своя специфика и свои приколы. В сишке быстрее и чаще всего прилетает use-after-free или segfault, перед тем, как прилетит что-то еще. Если это не проблема синхронизации и все происходит в одном потоке, то разраба, который делает p->A после free(p) нужно отправить в больничку провериться на здоровье. Никакой ЯП без укзателей тут не поможет, он и там накосячит полные штаны.

slew
()
Ответ на: комментарий от slew

Ну да, сначала придумали якобы удобство unique_ptr, а потом, чтоб это можно было использовать, навесили туда запреты копирования и мувинг only. Уже подпорки.

Эталонный фейспалм. Это не подпорки, а контроль семантики «единственный владелец» на этапе компиляции. Те самые «простые и интуитивные правила», в сторону которых ты выше уже плевался. Тогда я постеснялся, а сейчас самый раз. Продолжать разговор не вижу смысла.

dimgel ★★★★★
()
Последнее исправление: dimgel (всего исправлений: 2)
Ответ на: комментарий от dimgel

Это не подпорки, а контроль семантики «единственный владелец» на этапе компиляции

Да, дерьмецо-то из головы вытряси, потому поговорим.

slew
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.