У нас в производстве есть несколько систем сборки, о которых никто не заботится, и на этих машинах работают старые версии GCC, такие как GCC 3 или GCC 2.
И я не могу уговорить руководство обновить его до более свежего: мол, «если не сломалось, не чини».
Поскольку мы поддерживаем очень старую кодовую базу (написанную в 80-х), этот код C89 отлично компилируется на этих компиляторах.
Но я не уверен, что использовать эти старые вещи - хорошая идея.
У меня вопрос:
Может ли использование старого компилятора C поставить под угрозу безопасность скомпилированной программы?
ОБНОВИТЬ:
Тот же код создается Visual Studio 2008 для целей Windows, а MSVC еще не поддерживает C99 или C11 (я не знаю, поддерживает ли более новый MSVC), и я могу собрать его на своем компьютере с Linux, используя последнюю версию GCC. Так что, если мы просто добавим новый GCC, он, вероятно, будет работать так же хорошо, как и раньше.
-O3 -Wall -Wextra -fsanitize=undefined
помощью современных gcc и clang, должно помочь.Ответы:
На самом деле я бы сказал наоборот.
Есть ряд случаев, когда поведение не определено стандартом C, но когда очевидно, что произойдет с «глупым компилятором» на данной платформе. Например, разрешение переполнения знакового целого числа или доступ к одной и той же памяти через переменные двух разных типов.
Последние версии gcc (и clang) начали рассматривать эти случаи как возможности оптимизации, не заботясь о том, изменяют ли они поведение двоичного файла в состоянии «неопределенное поведение». Это очень плохо, если ваша кодовая база была написана людьми, которые относились к C как к «портативному ассемблеру». Со временем оптимизаторы начали обращать внимание на все большие и большие фрагменты кода при выполнении этих оптимизаций, увеличивая вероятность того, что двоичный файл в конечном итоге будет делать что-то иное, чем «то, что будет делать двоичный файл, созданный глупым компилятором».
Есть переключатели компилятора для восстановления «традиционного» поведения (-fwrapv и -fno-strict-aliasing для двух, о которых я упоминал выше), но сначала вы должны узнать о них.
Хотя в принципе ошибка компилятора может превратить совместимый код в брешь в безопасности, я считаю, что риск этого незначительный в общем плане.
источник
people who treated C like a "portable assembler"
разве это не то, что есть C?Оба варианта действий сопряжены с риском.
У старых компиляторов есть преимущество зрелости, и все, что в них было сломано, вероятно (но нет гарантии) было успешно исправлено.
В этом случае новый компилятор - потенциальный источник новых ошибок.
С другой стороны, новые компиляторы поставляются с дополнительными инструментами :
Обработка двоичного файла с помощью дезинфицирующих средств (Address Sanitizer, Memory Sanitizer или Undefined Behavior Sanitizer) с последующим его фаззингом (например, с использованием American Fuzzy Lop ) выявила уязвимости в ряде известных программ, см., Например, эту статью LWN.net .
Эти новые инструменты и все будущие инструменты будут для вас недоступны, если вы не обновите компилятор.
Оставаясь на недостаточно мощном компиляторе, вы кладете голову в песок и скрещиваете пальцы, что уязвимости не обнаружено. Если ваш продукт - целевая аудитория, я призываю вас пересмотреть свое мнение.
Примечание: даже если вы НЕ обновляете производственный компилятор, вы все равно можете захотеть использовать новый компилятор для проверки на уязвимость; Имейте в виду, что, поскольку это разные компиляторы, гарантии уменьшаются.
источник
Ваш скомпилированный код содержит ошибки, которые могут быть использованы. Ошибки происходят из трех источников: ошибки в исходном коде, ошибки в компиляторе и библиотеках и неопределенное поведение в исходном коде, которое компилятор превращает в ошибку. (Неопределенное поведение - это ошибка, но еще не ошибка в скомпилированном коде. Например, i = i ++; в C или C ++ это ошибка, но в вашем скомпилированном коде она может увеличивать i на 1 и иметь значение Ok, или установить я в какой-то барахло и буду жучком).
Вероятно, количество ошибок в вашем скомпилированном коде невелико из-за тестирования и исправления ошибок из-за отчетов об ошибках клиентов. Так что изначально могло быть большое количество ошибок, но теперь их нет.
Если вы обновитесь до более нового компилятора, вы можете потерять ошибки, которые были внесены ошибками компилятора. Но все эти ошибки будут ошибками, которые, насколько вам известно, никто не нашел и никто не использовал. Но новый компилятор может иметь ошибки сам по себе, и, что важно, новые компиляторы имеют более сильную тенденцию превращать неопределенное поведение в ошибки в скомпилированном коде.
Так что в вашем скомпилированном коде будет много новых ошибок; все ошибки, которые могут найти и использовать хакеры. И если вы не проведете много тестирования и не оставите свой код клиентам на долгое время для поиска ошибок, он будет менее безопасным.
источник
getaddrinfo()
: access.redhat.com/articles/2161461 . Этот пример на самом деле не является недостатком безопасности компилятора, но через 10+ лет обязательно появятся известные исправленные недостатки.Если он не сломался, не чините его
Ваш босс кажется правым, говоря, что это более важный фактор - защита входов, выходов и переполнения буфера. Их отсутствие - неизменно самое слабое звено в цепи с этой точки зрения, независимо от используемого компилятора.
Однако, если кодовая база устарела и была проведена работа по смягчению слабых мест используемого K&R C, таких как отсутствие безопасности типов, небезопасные fgets и т. Д., Взвесите вопрос « Будет ли обновлен компилятор до более современного C99? Стандарты / C11 ломают все? "
При условии, что существует четкий путь для перехода на новые стандарты C, который может вызвать побочные эффекты, может быть лучше попытаться выполнить форк старой кодовой базы, оценить ее и добавить дополнительные проверки типов, проверки работоспособности и определить, выполняется ли обновление до более новый компилятор имеет какое-либо влияние на наборы данных ввода / вывода.
Затем вы можете показать своему боссу: « Вот обновленная база кода, отремонтированная, в большей степени в соответствии с принятыми в отрасли стандартами C99 / C11 ... ».
Это риск, который нужно взвесить очень осторожно , сопротивление изменениям может проявиться в этой среде и может отказаться прикасаться к новым материалам.
РЕДАКТИРОВАТЬ
Просто откинулся на несколько минут, понял это, код, сгенерированный K&R, может работать на 16-битной платформе, есть вероятность, что обновление до более современного компилятора может действительно сломать базу кода, я думаю с точки зрения архитектуры, будет сгенерирован 32-битный код , это может иметь смешные побочные эффекты на структурах , используемых для ввода / вывода массивов данных, что является еще одним огромным фактором взвешивать тщательно.
Кроме того, поскольку OP упомянул об использовании Visual Studio 2008 для создания базы кода, использование gcc может вызвать внесение в среду либо MinGW, либо Cygwin, что может повлиять на изменение среды, если только цель не предназначена для Linux, тогда это будет стоит попробовать, возможно, придется включить дополнительные переключатели в компилятор, чтобы минимизировать шум в старой кодовой базе K&R, другая важная вещь - провести большое тестирование, чтобы убедиться, что ни одна функциональность не нарушена, может оказаться болезненным упражнением.
источник
Конечно, может, если старый компилятор содержит известные ошибки, которые, как вы знаете, могут повлиять на вашу программу.
Вопрос в том, не так ли? Чтобы знать наверняка, вам нужно будет прочитать весь журнал изменений от вашей версии до текущей даты и проверить каждую ошибку, исправленную за эти годы.
Если вы не обнаружите свидетельств ошибок компилятора, которые могли бы повлиять на вашу программу, обновление GCC просто ради этого кажется немного параноидальным. Вы должны иметь в виду, что более новые версии могут содержать новые ошибки, которые еще не обнаружены. В последнее время было внесено множество изменений с поддержкой GCC 5 и C11.
При этом код, написанный в 80-х, скорее всего, уже заполнен до краев дырами в безопасности и полагается на плохо определенное поведение, независимо от компилятора. Здесь мы говорим о предварительном стандарте C.
источник
Существует угроза безопасности, когда злонамеренный разработчик может проникнуть через черный ход через ошибку компилятора. В зависимости от количества известных ошибок в используемом компиляторе бэкдор может выглядеть более или менее незаметным (в любом случае, дело в том, что код правильный, даже если он запутан, на уровне исходного кода. Анализ исходного кода и тестирование с использованием компилятор без ошибок не найдет бэкдор, потому что бэкдор не существует в этих условиях). Для получения дополнительных очков отрицания злонамеренный разработчик может также самостоятельно искать ранее неизвестные ошибки компилятора. Опять же, качество маскировки будет зависеть от выбора найденных ошибок компилятора.
Эта атака проиллюстрирована на программе sudo в этой статье . bcrypt написал отличное продолжение минификаторов Javascript .
Помимо этого беспокойства, эволюция компиляторов была использовать неопределенное поведение более и более и более агрессивно, так что старый C код , который был написан в духе доброй воли будет на самом деле более безопасным скомпилирован с компилятором от времени, или составленного на -O0 (но некоторые новые программные оптимизации использования UB вводятся в новых версиях компиляторов даже при -O0 ).
источник
Старые компиляторы могут не иметь защиты от известных хакерских атак. Например, защита от разрушения стека не была представлена до GCC 4.1 . Так что да, код, скомпилированный с помощью старых компиляторов, может быть уязвим в том смысле, от которого защищают новые компиляторы.
источник
Еще один аспект, о котором нужно беспокоиться, - это разработка нового кода .
Старые компиляторы могут иметь другое поведение для некоторых языковых функций, чем то, что стандартизовано и ожидается программистом. Это несоответствие может замедлить разработку и привести к появлению незаметных ошибок, которыми можно воспользоваться.
Старые компиляторы предлагают меньше возможностей (в том числе языковых!) И не оптимизируются. Программисты постараются обойти эти недостатки - например, заново реализовать недостающие функции или написать умный код, который непонятен, но работает быстрее, - создавая новые возможности для создания мелких ошибок.
источник
Неа
Причина проста: в старом компиляторе могут быть старые ошибки и эксплойты, но в новом компиляторе будут новые ошибки и эксплойты.
Вы не «исправляете» какие-либо ошибки, обновляя компилятор до нового. Вы переключаете старые ошибки и эксплойты на новые ошибки и эксплойты.
источник
Что ж, существует более высокая вероятность того, что любые ошибки в старом компиляторе хорошо известны и задокументированы, чем при использовании нового компилятора, поэтому можно предпринять действия, чтобы избежать этих ошибок, кодируя их. Так что этого недостаточно в качестве аргумента для обновления. У нас те же обсуждения, где я работаю, мы используем GCC 4.6.1 на базе кода для встраиваемого программного обеспечения, и существует большое нежелание (среди руководства) обновляться до последней версии компилятора из-за опасений новых, недокументированных ошибок.
источник
Ваш вопрос состоит из двух частей:
Возможно, вы сможете ответить на оба вопроса, обнаружив уязвимость в существующей кодовой базе и показывая, что более новый компилятор обнаружил бы ее. Конечно, ваше руководство может сказать: «Вы обнаружили это с помощью старого компилятора», но вы можете указать, что это требует значительных усилий. Или вы запускаете его через новый компилятор, чтобы найти уязвимость, а затем использовать ее, если вы можете / можете скомпилировать код с новым компилятором. Возможно, вам понадобится помощь дружелюбного хакера, но это зависит от доверия к ним и от возможности / разрешения показать им код (и использовать новый компилятор).
Но если ваша система не подвержена хакерским атакам, вам, возможно, стоит больше интересоваться, повысит ли ваша эффективность обновление компилятора: MSVS 2013 Code Analysis довольно часто обнаруживает потенциальные ошибки намного раньше, чем MSVS 2010, и более или менее поддерживает C99 / C11 - не уверен, что это официально, но объявления могут следовать за операторами, и вы можете объявлять переменные в
for
-loops.источник