Использует ли устаревший компилятор C угрозу безопасности?

У нас есть некоторые системы сборки в производстве, о которых никто не заботится, и эти машины используют древние версии GCC, такие как GCC 3 или GCC 2.

И я не могу убедить руководство обновить его до более позднего: они говорят: "Если не сломано, не исправляйте".

Поскольку мы сохраняем очень старую базу кода (написанную в 80-х годах), этот код C89 компилируется на этих компиляторах очень хорошо.

Но я не уверен, что это хорошая идея использовать эти старые вещи.

Мой вопрос:

Может ли старый компилятор C скомпрометировать безопасность скомпилированной программы?

UPDATE:

Тот же код создается объектами Visual Studio 2008 для Windows, а MSVC еще не поддерживает C99 или C11 (я не знаю, работает ли новый MSVC), и я могу создать его на своем ящике Linux, используя последние GCC. Поэтому, если мы просто запустим новый GCC, он, вероятно, будет построен так же хорошо, как раньше.

Ответ 1

Собственно, я бы сказал, что обратное.

Существует несколько случаев, когда поведение undefined по стандарту C, но где очевидно, что произойдет с "немым компилятором" на данной платформе. Такие случаи, как допустимое целое число со знаком для переполнения или доступа к одной и той же памяти, хотя переменные двух разных типов.

Недавние версии gcc (и clang) начали рассматривать эти случаи как возможности оптимизации, не заботясь о том, изменяют ли они поведение бинарных файлов в состоянии "undefined". Это очень плохо, если ваша кодовая база была написана людьми, которые рассматривали C как "переносимый ассемблер". С течением времени оптимизаторы начали смотреть на большие и большие куски кода при выполнении этих оптимизаций, увеличивая вероятность того, что двоичный код в конечном итоге сделает что-то другое, чем "то, что сделает двоичный файл, созданный немым компилятором".

Существуют переключатели компилятора для восстановления "традиционного" поведения (-fwrapv и -fno-strict-aliasing для двух упомянутых выше), но сначала вы должны знать о них.

Хотя в принципе ошибка компилятора может превратить совместимый код в отверстие безопасности, я бы подумал о том, что это может быть неоправданным в великой схеме вещей.

Ответ 2

В обоих направлениях действия существуют риски.


Старые компиляторы имеют преимущество зрелости, и все, что было сломано в них, вероятно (но без гарантии) было успешно выполнено.

В этом случае новый компилятор является потенциальным источником новых ошибок.


С другой стороны, новые компиляторы поставляются с дополнительными инструментами:

  • GCC и Clang теперь используют дезинфицирующие средства, которые могут заставить среду выполнения обнаруживать поведение undefined различных типов (Chandler Carruth, команда Google Compiler, заявила в прошлом году, что ожидает, что они достигнут полного охвата)
  • Clang, по крайней мере, имеет функции упрочнения, например Integrity Flow Flow - это обнаружение hi-jacks управляющего потока, есть также упрочняющие инструменты для защиты от разбития стека атаки (путем разделения части потока управления стека из части данных); упрочняющие функции, как правило, являются низкими накладными расходами (1% накладных расходов ЦП).
  • Clang/LLVM также работает над libFuzzer, инструментом для создания инструментальных модульных модульных тестов, которые исследуют входное пространство тестируемой функции (по настраивая ввод, чтобы принимать не-все-таки исследованные пути выполнения)

Приспособление вашего двоичного файла к дезинфицирующим средствам (адрес Sanitizer, дезактиватор памяти или undefined Behavior Sanitizer), а затем fuzzing it (с помощью American Fuzzy Lop) раскрыл уязвимости в ряде громких программ, см., например, эту статью LWN.net.

Эти новые инструменты и все будущие инструменты недоступны для вас, если вы не обновите свой компилятор.

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


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

Ответ 3

Скомпилированный код содержит ошибки, которые могут быть использованы. Ошибки исходят из трех источников: ошибки в исходном коде, ошибки в компиляторе и библиотеках и поведение undefined в исходном коде, что компилятор превращается в ошибку. (Undefined поведение является ошибкой, но пока не является ошибкой в ​​скомпилированном коде. В качестве примера я = я ++; в C или С++ есть ошибка, но в вашем скомпилированном коде он может увеличиться на я на 1 и быть Ok, или установите я в некоторый барахл и будьте ошибкой).

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

Если вы перейдете на новый компилятор, вы можете потерять ошибки, которые были внесены в ошибки компилятора. Но эти ошибки были бы ошибками, которые, насколько вам известно, никто не нашел и никто не использовал. Но у нового компилятора могут быть ошибки сами по себе, и важно, чтобы более новые компиляторы имели более сильную тенденцию превращать поведение undefined в ошибки в скомпилированном коде.

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

Ответ 4

Если он не сломался, не исправляйте его

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

Однако, если база кода является древней, и была создана работа по смягчению слабых мест используемого K & RC, такого как отсутствие безопасности типа, небезопасные фэки и т.д., взвешивает вопрос "Будет ли усовершенствование компилятора к более современным стандартам C99/C11 сломать все?"

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

Затем вы можете показать его своему боссу: "Здесь обновленная база кода, реорганизованная, больше соответствует промышленным стандартам C99/C11...".

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

ИЗМЕНИТЬ

Просто откинулся на несколько минут, так понял, что код K & R сгенерированный может работать на 16-битной платформе, скорее всего, обновление до более современного компилятора может фактически сломать базу кода, я думаю об архитектуре, 32-битный код был бы сгенерирован, это может иметь смешные побочные эффекты для структур, используемых для наборов данных ввода/вывода, то есть другого огромного фактора для взвешивания.

Кроме того, поскольку OP упомянул об использовании Visual Studio 2008 для создания базы кода, использование gcc могло бы привести к появлению в среде MinGW или Cygwin, которые могли бы повлиять на изменение среды, если только целью для Linux не является это было бы целесообразно, возможно, придется включить дополнительные ключи в компилятор, чтобы минимизировать шум на старой базе кода K & R, другая важная вещь - провести много испытаний, чтобы гарантировать отсутствие функциональности, может оказаться быть болезненным упражнением.

Ответ 5

Может ли старый компилятор C скомпрометировать безопасность скомпилированной программы?

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

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

Если вы не найдете доказательств ошибок компилятора, которые повлияют на вашу программу, обновление GCC только ради этого кажется немного параноидальным. Вы должны иметь в виду, что новые версии могут содержать новые ошибки, которые еще не обнаружены. Недавно были внесены изменения с поддержкой GCC 5 и C11.

При этом код, написанный в 80-х годах, скорее всего, уже заполнен до краев дырками безопасности и зависит от плохо определенного поведения, независимо от того, компилятор. Мы говорим о предварительном стандарте C здесь.

Ответ 6

Существует риск для безопасности, когда вредоносный разработчик может прокрасть заднюю дверь через ошибку компилятора. В зависимости от количества известных ошибок в используемом компиляторе бэкдор может выглядеть более или менее незаметным (в любом случае, дело в том, что код верен, даже если он запутан, на исходном уровне. Исходные коды и тесты с использованием не-багги-компилятор не найдет бэкдор, потому что в этих условиях бэкдор не существует). Кроме того, вредоносный разработчик может также искать ранее неизвестные ошибки компилятора самостоятельно. Опять же, качество камуфляжа будет зависеть от выбора найденных ошибок компилятора.

Эта атака проиллюстрирована в программе sudo в в этой статье. bcrypt написал большое продолжение для Javascript minifiers.

Помимо этой проблемы, эволюция компиляторов C заключалась в использовании undefined поведения больше и больше и более агрессивно, поэтому старый код C, написанный добросовестно, на самом деле будет более безопасным скомпилированный с компилятором C из времени или скомпилированный на -O0 (но некоторые новые программные оптимизации UB-оптимизации вводятся в новых версиях компиляторов даже при - O0).

Ответ 7

Старые компиляторы могут не иметь защиты от известных хакерских атак. Например, защита от разбивания стека не вводилась до GCC 4.1. Так что да, код, составленный с более старыми компиляторами, может быть уязвим тем способом, который защищают более новые компиляторы.

Ответ 8

Еще один аспект, о котором нужно беспокоиться, - это разработка нового кода.

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

Старые компиляторы предлагают меньше возможностей (включая языковые возможности!) и не оптимизируются. Программисты будут взламывать эти недостатки -— например путем переопределения недостающих функций или написания умного кода, который неясен, но работает быстрее — создавая новые возможности для создания тонких ошибок.

Ответ 9

Неа

Причина проста, старый компилятор может иметь старые ошибки и эксплойты, но новый компилятор будет иметь новые ошибки и эксплойты.

Не исправляйте никаких ошибок при обновлении до нового компилятора. Вы переключаете старые ошибки и эксплойты на новые ошибки и эксплойты.

Ответ 10

Хорошо, существует большая вероятность того, что любые ошибки в старом компиляторе хорошо известны и задокументированы, а не с использованием нового компилятора, поэтому можно предпринять действия, чтобы избежать ошибок, связанных с их кодированием. Таким образом, это недостаточно, как аргумент для обновления. У нас те же обсуждения, в которых я работаю, мы используем GCC 4.6.1 на базе кода для встроенного программного обеспечения, и есть большая неохота (среди руководства) для обновления до последнего компилятора из-за страха за новые недокументированные ошибки.

Ответ 11

Ваш вопрос разбивается на две части:

  • Явно: "Существует ли больший риск при использовании старого компилятора" (более или менее как в вашем заголовке).
  • Неявно: "Как я могу убедить руководство обновить"

Возможно, вы можете ответить как на обнаружение уязвимости в вашей существующей базе кода, так и на то, что новый компилятор обнаружит ее. Разумеется, ваше руководство может сказать "вы обнаружили, что со старым компилятором", но вы можете указать, что это требует значительных усилий. Или вы запускаете его через новый компилятор, чтобы найти эту уязвимость, а затем использовать ее, если у вас есть возможность/разрешить компиляцию кода с помощью нового компилятора. Вам может понадобиться помощь от дружелюбного хакера, но это зависит от того, доверяет им и может/разрешено показывать им код (и использовать новый компилятор).

Но если ваша система не подвержена хакерам, вам, возможно, следует больше интересоваться повышением эффективности компилятора: анализ кода MSVS 2013 довольно часто находит потенциальные ошибки намного раньше, чем MSVS 2010, и он более или менее поддерживает C99/C11 - не уверен, что он официально, но декларации могут следовать за утверждениями, и вы можете объявлять переменные в for -loops.