Доступен новый выпуск утилиты sudo 1.9.17p2, используемой для организации выполнения команд от имени других пользователей. В новом выпуске устранена проблема, приводившая при определённом стечении обстоятельств к отправке сигнала SUGHUB (завершение работы) не запущенному процессу, а всем процессам в системе...Подробнее: https://www.opennet.me/opennews/art.shtml?num=63633
> без должного анализа возвращённого ранее кода ошибкиВиноват си, потому что не дает sum types. То, что разраб забыл проверить -- простительно, потому что мозг -- это мясо. Мы не можем от мяса требовать 100%-ного анализа кода. К счастью, есть язык, который автоматизирует проверки. Он бы это выявил на этапе компиляции и подсказал мясу: "тут может вернуться ошибка". Мясо бы кивнуло и поблагодарило чудо-язык за техническую помощь.
а gcc разве не выдаёт такие варнинги при компиляции?
и использование статических анализаторов разве не является обязательным при разработке критически важного софта?
Использование костылей разве не является обязательным при ходьбе?
Если вы откроете патч (https://github.com/sudo-project/sudo/commit/fb208d383af27a07...), то обнаружите, что pgrp приезжает из ec->cmnd_pid, который устанавливается вообще в другом месте, кем попало, как попало, аж в трёх си-файлах, да и там либо явно (= -1), либо очень косвенно (= cstat.val, = sudo_debug_fork()), а не из результата выполнения стандартной библиотечной функции. Компиляторный угадав тут явно бесполезен, потому что ему никто никогда не подскажет, используется ли потом это поле структуры в другом месте без проверки или просто авторы с привычками времён 80486 опять экономят байты исполняемого кода, удачно переиспользуя -1 по своему усмотрению.И, да, Result/Either type тут действительно сэкономил бы время всем, потому что компилятор бы гавкнул на попытку использовать этот тип как аргумент kill(), и сделал бы это быстро и надёжно, в отличие от статических анализаторов, которым нужно проверить миллион инвариантов среди сотен функций из десятков файлов, не запутаться в них и не вылететь по исчерпанию памяти. Если, конечно, какой-то анализатор вообще надоумили проверить, что в kill() передаётся -1 (в чём я сомневаюсь, потому что отрицательные аргументы у kill легитимны и используются гораздо чаще, чем может показаться), потому что анализировать коды возвратов тут, похоже, бесполезно (см. выше).
Они сейчас вставили проверку на -1. Ну ок, а если прилетит -2? С таким подходом ни какие расты не спасут.Их нельзя за это винить: Open Source отродясь был хобби для энтузиастов - где каждый волен галлюционировать как ему взимается. Проблему создали те, кто решил тащить создаваемый таким способом код в энтерпрайз.
> Open Source отродясь был хобби для энтузиастов - где каждый волен галлюционировать как ему взимается.Ты больной? Оупен сорс - это модель распространения исходников и не более, к качеству кода это вообще никак не относится. Или ты думаешь в закрытом софте как иначе пишут и не галлюцинируют? Достаточно венду вспомнить с её троянами, вымогателями и порнобаннерами
Больной здесь скорее тот, кто докопался до формального лпределения.
И да, в корпаниях пишут код иначе - там есть проверяющие.
В опенсорсе же таких часто нет. И да, опенсорц это хобби, даже Линус когда ядро писал был студентом и это был его хобби проект. Без интереса корпораций линукс был бы сейчас в лучшем случае где-то среди бздей, а в худшем - хурдом.
А -2 это тоже валидное значение. Всё, что необходимо - сделать сильнотипизированную обёртку. Везде, где мы снаружи получаем какое-то значение, мы его парсим в тип. Примерно как фейсконтроль в баре. Проверяем, что мы получаем. Если это не, то, что ожидаемо в конкретном контексте - выводим ошибку. Чтонибудь вроде Result<ProcessId, i32> даже сойдёт. Окей, в некоторых местах будет Result<GroupId, i32>. Или enum { ProcessId(u32), GroupId(u32), ... }. И с другой стороны, когда нам надо вызвать kill, то мы прям перед этим проверяем, если в конкретном месте имеет смысл только pid, но не gid. Нам ведь надо превратить тип-сумму обратно в число.Просто делаем процесс явным всегда. Это сильно упрощает чтение кода, при том это самое чтение даёт больше информации. Более ёмкий и более читабельный код уменьшает вероятность логических ошибок. Поддержка становится проще и всё такое. А освободившееся время, которое не потрачено на пошаговый дебаг, можно использовать для написания тех же тестов например. Ведь не то, чтоб у нас были неограниченные ресурсы для написания и поддержки каждого мелкого винтика unix-way системы.
Зачем для проверки входных данных переходить на другой язык?
> Зачем для проверки входных данных переходить на другой язык?Валидация и парсинг это разные штуки. В сишечке просто нет достаточно сильной системы типов, чтоб в неё можно было оборачивать результаты.
Зачем для проверки входных данных какая-то сильная система типов и прочее, если это делается простым if-else, ну или switch-case, ну или исключениями, если речь о С++?
> Зачем для проверки входных данных какая-то сильная система типов и прочее, если
> это делается простым if-else, ну или switch-case, ну или исключениями, если
> речь о С++?Очень напоминает аргумент «зачем нам вообще типы в сигнатурах функций, если можно просто написать миллион интеграционных тестов и assert()-ов». Последствия тоже похожие: у одних в рантайме всё равно проскакивают undefined is not a function, а другие почему-то постоянно забывают добавлять эти простые, нет, ПРОСТЕЙШИЕ if-else вокруг kill(). Один раз проставленный тип ругается на всех людей независимо от того, насколько они внимательные (напомню, 100% внимательных нет, даже если они под действием [запрещено роскомнадзором] и зоркого взгляда Ким Чен Ына с револьвером в руках). Зачем в обоих случаях делать работу за компилятора?
> какая-то сильная система типов
Для такой простой ошибки не нужно иметь дело со всякими Хиндли-Милнерами, достаточно сахара вокруг tagged union, который любому компилятору дастся без проблем.
Для валидации, да, достаточно if/switch. Но парсинг это не валидация, а нечто большее:
https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va.../С этим сложновато работать, если у тебя есть только Си. C++ же будет излишне многословен, а местами неуклюж. Лучше всего взять язык, который является функциональным, либо испытал сильное влияние функциональных языков. Haskell, Rust, Ocalm, может ещё что-то такое. Строгая сильная типизация, вывод типов, паттернматчинг, вот это вот всё. Правда большая часть ФП-языков нуждаются в GC, что не очень подходит для утилиток вроде sudo.
Общая идея в том, чтоб, полагаясь на мощь современных систем типов, позволить компилятору проверять корректность использования данных. Есть некоторая разница между просто int и enum { A, B(int), C }. Тип-сумма семантически несёт в себе гораздо больше информации. Гораздо сложнее ошибиться, когда ты всегда явно описываешь все преобразования. А пользоваться подобной системой сильно проще и надёжнее, чем пачкой сторонних анализаторов.
Выбирать язык целого проекта по такому критерию это какое-то безумие. Есть более простые работающие способы.
Критерий - язык, который позволяет эффективнее достичь поставленной задачи. Очень безумно, да. Но так можно было.То, о чём я писал выше - весьма конкретный пример использования свойств продвинутой системы типов. Для решения весьма конкретной задачи в микромасштабе.
В макромасштабе, но всё ещё оставаясь в рамках контекста: у нас есть sudo.
Основное требование к sudo - корректность. Любая логическая ошибка является уязвимостью.
Идеальное решение - формальная верификация. Математическое доказательство корректности.Идеальное решение недоступно по причине недостатка ресурсов. Но мы можем взять язык с продвинутым встроенным анализатором. Решение не идеальное, но практичное.
Второе по важности требование - потребление ресурсов. Мы хотим максимальную производительность, минимальное потребление памяти, компактный бинарник и так далее. Но только при условии полного соблюдения первого условия.
Плюс куча всяких второстепенных требований. От наличия мотивированных программистов (у нас ведь OpenSource) до маркетингового булшита. Это всё тоже имеет некоторый вес на самом деле, но в данном контексте это второстепенно.
Есть и более простой способ. Захотелось - пошёл и сделал. Просто. Без всякой задней мысли.
Ну, если взять функциональный язык и написать на нём чисто верифицирующие прослойки, то наверное это имеет смысл.
А где же "миллионы глаз", которые пропустили эту ошибку ещё на этапе сборки?
У семи нянек дитя с CVE
у sudo настолько огромная кодовая база что отдельному программисту практически невозможно проверить все
Тогда получается, что надёжность Linux - это просто слова?
О 100% надёжности Linux никогда не говорили.
О, как! А как же "Linux работает на N компьютеров, входящих в топ-500"? Неужели обманули? 😆
Работает. А надёжность то здесь причём?
Так его пихают туда просто чтобы был?
Да уж, умственные способности вендоров поражают.. 😆
Значит, масштабируется на кластерах хорошо. Чтобы работал и задачи по моделированию ядерных взрывов крутил (Лос Аламос, Ливермор) вместо натурных испытаний, по моделилованию погоды (нужно всем странам).
Ну ты и демагог.
ваша аппаратная архитектура байдезинг ненадежна, о чем речь вообще.
Размер кодовой базы не причём. Налажал автор предыдущего изменения, а патч там был мелкий. В отладочном сообщении он прямо писал, что собирается вызвать killpg, но строчкой ниже вызывал kill. Если такие ошибки пропускают, значит с ревью изменений там на самом деле все плохо.
Я своими двумя посмотрел и снёс этот ваш sudo из системы. Чтобы пакеты не выпендривались, сделал псевдопакет без судо.
sudo вообще не нужен. Тем более на localhost.
C не виноват в том, что люди не умеют докусентацию читать
Ниче, скоро ИИ её читать будет, новости о новом бэкдоре станут чаще здесь мелькать..
> Виноват си, потому что не дает sum typesв ядре это роскошь.
В нормальном языке типы не утекают в исполняемый код. А если именно это и надо, то пилите struct с интом в начале структуры и всеми необходимыми структурами в union ниже. Великолепно работает.
Угу, куча хлама в ядре - не роскошь, а это - вдруг роскошь.
killpg - это алиас для обычной остановки постгреса
> При передаче отрицательного значения группы поведение не определенСишное мышление.
Когда привык, что UB это неотъемлемая часть системы и переносишься это на уровень пользователя.
Если я вашу rust программу (без шизофренической проверки каждого аргумента для каждой функции) запущу и на следующий день другой компонент системы, который вы в rust не контролируете (структура или код ошибки из ядра, данные из файла, из прилинкованной библиотеки), то в вашем расте внезапно тоже появится UB, потому что *ТЫ* не проверил входные данные.
> в вашем расте внезапно тоже появится UB, потому что *ТЫ* не проверил входные данные.В худшем случае не UB, а паника. Если, допустим, у меня есть тип ProcessId, и я не проверил входные данные, прежде чем делать ProcessId::from_int(pid), то ProcessId::from_int выкинет панику. Либо, альтернативный подход к этому -- не паника, а Result<ProcessId,Error> возвращаемый из from_int. В этом случае, раст заставит обработать ошибку, то есть входные данные будут проверены и ошибка будет обработана.
> без шизофренической проверки каждого аргумента для каждой функции
Раст больше заточен на проверку возвращаемых значений. Аргументы проверять нет нужды, потому что их свойства гарантируются по-построению. Нет смысла проверять &str на utf8-валидность, потому что &str по построению валиден.
Проверки аргументов тоже бывают, тот же index проверяет входной аргумент usize, но вот это как раз скорее отход от Rust-way.
В Расте обычно не проверки аргументов из примитивных типов, а предварительное преобразование из примитивных в оберточные типы. Проверка делается в конструкторе.Без проверок никуда, но с таким подходом их будет намного меньше (если это pid, то мы знаем, что он не может быть -1, и пишем это один раз), а аргументом принимаем уже тип pid, который по определению (если мы правильно написали его конструктор из инта) валиден.
Такой подход, можно сказать, заставляет написать все проверки.
Ни когда не понимал, зачем такую косую утилиту пихают почти во все дистры линукса
Потому что пользователей GUI пугают терминалы? )
Потому что он не в курсе привилегий и считает себя богом своей машинки, при этом ничего не понимая в плане безопасности надо принудительно разграничивать? )
>При передаче отрицательного значения группы поведение не определеноКосяк killpg(). Они скажут, что тот кто использует killpg() должен контролировать что передает её. Но killpg() - часть системы, и приумножать хаос своей неопределенность не должна. Тем более проверка на входе для неё не критичная в плане производительности. Это все, может быть оставлено для костылей? Но ведь поведение кода не определено при таком фактическом значение!
Описание в новости не имеет отношения к реальности, кстати. В патче не подчищают за killpg(), а меняют kill() на killpg(), а у kill() поведение при отрицательном pid как раз-таки определено чётко. Что, конечно, не отменяет ногострельности интерфейса в современных руках.
Хороши "миллионы глаз", нечего сказать. Уязвимость случайно (?) появилась в сентябре прошлого года и только сейчас заметили, что sudo неправильно обрабатывает запросы..
Ниче, ИИ все эти "случайности" найдёт.. и добавит новые..
На линуксах баг не воспроизводится. Проблему обнаружили на AIX, когда до них доехала эта версия. То что она приехала к ним через год, для энтерпрайзов это нормально.
Не «не воспроизводится», а «ещё не успели воспроизвести». Там же не только aix, но и огромная куча людей на сервере, например; давно вы такое видели на серверах? А /dev/pts у линукса тоже не резиновый, на секундочку.
Когда портируют ПО из Linux в BSD, необходимо всё проверять, т.к. многие самые обычные вещи работают по-разному. Всегда проверяю.
Вот поэтому и существует Debian stable с проверенными временем пакетами.
Вы же об этом https://www.linux.org.ru/news/linux-general/17448413 Debian Stable сейчас пишете?
Тебе разрешаю на experimental сидеть.
> Debian stable с проверенными временем дырявыми пакетами.Так будет точнее)
У них минимум 3 года сквид был с 10+ штук уязвимостями. На который сам рахраю забил.
Но удалять дыярый пакет это не по деби(ли)ановски)
Может потому что squid надо самому всегда из исходников собирать, чтобы была поддержка HTTPS?
Сказочный дистрибутив 😂
Больно надо тебя уговаривать.
> Может потому что squid надо самому всегда из исходников собирать, чтобы была поддержка HTTPS?А в исходниках внезапно появятся фиксы?
Даже новость была "В прокси-сервере Squid выявлено 55 уязвимостей, 35 из которых пока не исправлены"
opennet.ru/opennews/art.shtml?num=59915Тут вопрос к Деби(ли)ану и его горе мейнтенерам, которые настолько упоролись по стабильности, что готовы выдавать юзерам дырявый крэп главное что оно "уже проверенное".
Перфекционизм - это плохо.