Чи використовує застарілий компілятор C ризик безпеки?


139

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

І я не можу переконати керівництво оновити його до більш недавнього: вони кажуть, "якщо не зламаються, не виправляйте".

Оскільки ми підтримуємо дуже стару базу коду (написану в 80-х роках), цей код C89 добре компілюється на цих компіляторах.

Але я не впевнений, що добре використовувати ці старі речі.

Моє запитання:

Чи може використання старого компілятора C погіршити безпеку компільованої програми?

ОНОВЛЕННЯ:

Цей же код створений Visual Studio 2008 для цілей Windows, і MSVC ще не підтримує C99 або C11 (я не знаю, чи є новіший MSVC), і я можу створити його на моєму скриньці Linux, використовуючи останню GCC. Тож якби ми просто впустили новіший GCC, він, ймовірно, створив би так само добре, як і раніше.


5
Цікаве запитання - це, можливо, варто прочитати також - developers.slashdot.org/story/13/10/29/2150211/… .. тож нові компілятори можуть також загрожувати безпеці при оптимізації.
Ніл

6
Ці старі версії gcc підтримують компіляцію в PIC / PIE для ASLR? Вони підтримують стек-канарки? W ^ X (NX)? Якщо ні, відсутність пом'якшення вразливості є вагомою причиною для оновлення.
EOF

12
Перегляд попереджень від gcc 4.x може негайно виявити цілий набір існуючих дірок у безпеці, які ви не знали, що у вас є.
OrangeDog

7
@OrangeDog: Чому gcc 4.x? gcc6 - поточна серія випусків, а gcc 5 вже деякий час. Але так, виправлення будь-яких проблем, виявлених -O3 -Wall -Wextra -fsanitize=undefinedсучасними gcc та clang, має допомогти.
Пітер Кордес

4
@OrangeDog GCC перейшов на маркетингові номери версій. GCC 5 заслужив основну помилку версії, оскільки вони змінили стандартні стандарти C і C ++ та libstdc ++ ABI. GCC 6 повинен був називатися 5.1.
zwol

Відповіді:


102

Насправді я б стверджував протилежне.

Є ряд випадків, коли поведінка не визначено стандартом C, але де очевидно, що буде з "тупим компілятором" на даній платформі. Такі випадки, як дозволяти підписаному цілому числу переповнювати або отримувати доступ до тієї самої пам'яті, хоч змінні двох різних типів.

Останні версії gcc (і clang) почали трактувати ці випадки як можливості оптимізації, не викликаючи бажання, якщо вони змінюють, як бінарний поводиться в умовах "невизначеної поведінки". Це дуже погано, якщо вашу кодову базу написали люди, які ставились до С як до "портативного асемблера". З часом оптимізатори почали дивитися на все більші та більші шматки коду, коли ці оптимізації збільшують шанс, що двійковий файл в кінцевому підсумку зробить щось інше, ніж "те, що зробить бінарний, побудований тупим компілятором".

Існують перемикачі компілятора, щоб відновити "традиційну" поведінку (-fwrapv і -fno-строгий-псевдонім для двох, про яких я згадував вище), але спочатку ви повинні знати про них.

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


13
Але цей аргумент працює обома способами. Якщо компілятор має передбачувану "невизначену поведінку", то зловмисно використовувати це може бути легше ...
André

18
@Andre Складений код все одно має передбачувану не визначену поведінку. Тобто, після того, як код був складений, будь-яка непередбачувана поведінка тепер передбачувана, у цій конкретно складеній версії.
користувач253751

6
people who treated C like a "portable assembler"хіба це не те, що C?
Макс

10
@Max Ця відповідь попереджає саме про те, що поняття "портативний асемблер" на практиці є принаймні застарілим завдяки сучасним оптимізаторам. І я б заперечив, що це ніколи не було концептуально правильно.
Теодорос Чатзіґянакікіс

6
Тут немає співчуття тим, хто покладається на невизначену поведінку і пізніше починає пожинати те, що посіяв. Це не означає, що нові компілятори за своєю суттю менш безпечні - це означає, що несумісний код був бомбою часу. Вину слід розподілити відповідно.
підкреслити_29

52

В обох напрямках існують ризики.


Старіші компілятори мають перевагу зрілості, і все, що було порушено в них, можливо, (але гарантії немає) було оброблено успішно.

У цьому випадку новий компілятор є потенційним джерелом нових помилок.


З іншого боку, нові компілятори поставляються з додатковими інструментами :

  • Зараз GCC і Clang оснащені дезінфікуючими засобами, які можуть призначати час виконання для виявлення різного роду невизначених типів поведінки (Чандлер Каррут, команда Google Compiler, в минулому році стверджував, що він очікує, що вони досягнуть повного покриття)
  • Принаймні, у Clang є особливості загартовування , наприклад, Control Flow Integrity - це виявлення високих роз'ємів контрольного потоку, також є пристрої для зміцнення для захисту від атак розбиття стека (шляхом відокремлення частини контрольної потоку стека від частини даних) ; характеристики загартовування, як правило, низькі накладні (<1% накладних процесорів)
  • Clang / LLVM також працює над libFuzzer , інструментом для створення інструментальних тестових блоків-тестів, які розумно досліджують вхідний простір функції тестуваної функції (налаштовуючи вхід для прийняття ще не досліджених шляхів виконання)

Інструментація вашого двійкового файлу із засобами дезінфекції (Address Sanitizer, Sanitizer Memory або Undefined Behavior Sanitizer), а потім його розмивання (використовуючи, наприклад, American Fuzzy Lop ) виявила вразливості у ряді гучних програм, див., Наприклад, цю статтю LWN.net .

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

Залишаючись на недостатньому компіляторі, ви кладете голову в пісок і схрещуєте пальці, щоб не було виявлено вразливості. Якщо ваш товар є цільовою ціною, я закликаю вас переглянути.


Примітка: навіть якщо ви НЕ обновляєте виробничий компілятор, ви можете скористатися новим компілятором, щоб перевірити наявність вразливості; майте на увазі, що оскільки це різні компілятори, то гарантії зменшуються.


1
+1 за клопотання згадати випадки, коли нові компілятори можуть бути більш безпечними, а не накопичувати на "b-але мій добрий старий UB" прокладку інших відповідей. це поверх багатьох інших вдосконалень, які вони пропонують, які не пов'язані безпосередньо із безпекою, але дають ще більше поштовху бути розумним сучасним.
підкреслюй_

Незважаючи на те, що виступає за «безпеку через незрозумілість»; Про помилки, які впливають на старі компілятори, відомі і загальнодоступні. Хоча я погоджуюся, що нові компілятори будуть вводити помилки, ці помилки ще не є загальнодоступними, як і попередні версії, що є певною безпекою, якщо ви часто оновлюєте додаток.
The6P4C

Чендлер Каррут такий милий і говорить про такі чудові речі. Я б вийшла за нього заміж, якби змогла.
Даніель Каміль Козар

46

Ваш компільований код містить помилки, які можна було б використати. Помилки надходять із трьох джерел: Помилки у вихідному коді, помилки у компіляторі та бібліотеках та невизначена поведінка у вихідному коді, що компілятор перетворюється на помилку. (Невизначена поведінка - це помилка, але ще не помилка у скомпільованому коді. Наприклад, i = i ++; у C або C ++ - помилка, але у вашому скомпільованому коді вона може збільшитися i на 1 і бути Ок, або встановити я на якийсь мотлох і бути помилкою).

Імовірно, кількість помилок у вашому складеному коді низька через тестування та виправлення помилок через звіти про помилки клієнтів. Тож, можливо, спочатку було велику кількість помилок, але це знизилось.

Якщо ви оновите до більш нового компілятора, ви можете втратити помилки, які були введені помилками компілятора. Але всі ці помилки були б помилками, які, на вашу думку, ніхто не знайшов і ніхто не експлуатував. Але новий компілятор може мати помилки самостійно, і, що важливо, новіші компілятори мають сильнішу тенденцію перетворювати невизначене поведінку в помилки у складеному коді.

Таким чином, у вашому складеному коді з’явиться маса нових помилок; всі помилки, які хакери могли знайти та використати. І якщо ви не зробите багато тестування і не залишите свій код разом із клієнтами, щоб знайти помилки на тривалий час, це буде менш безпечно.


6
Отже, іншими словами ... немає простого способу сказати, які проблеми представляє компілятор, і перемикаючи все, що ви робите, це отримати інший набір невідомих питань?
Джеремі Като

1
@JeremyKato: ну, є деякі випадки , коли ви також отримувати різний набір відомих проблем. Я не впевнений, які відомі вади безпеки є у самому компіляторі, але задля конкретного прикладу припустимо, що оновлення до нового компілятора означає також можливість приймати останній libc (при використанні старого означає неможливість щоб зробити це), тоді ви знаєте , що виправляєте цей недолік у getaddrinfo(): access.redhat.com/articles/2161461 . Цей приклад насправді не є вадою безпеки компілятора, але протягом 10+ років, мабуть, знайдуться деякі відомі виправлені недоліки.
Стів Джессоп

2
Так, насправді ця вада була введена лише в 2008 році, щоб запитуючий міг бути в безпеці від неї. Але моя думка не в тому, що стосується конкретного прикладу, це те, що існують відомі помилки, які старий інструментарій введе у ваш код. Тож коли ви оновлюєте, це правда, що ви вводите новий набір невідомих, але це ще не все, що ви робите . По суті, ви просто повинні здогадатися, чи є ви "більш захищеними", залишаючи відомий критичний недолік, який виправляє найновіший ланцюжок інструментів, або невідомі наслідки того, щоб згорнути кістки знову на все не визначене поведінку у вашому власному коді.
Стів Джессоп

19

Якщо це не зламалося, не виправляйте

Ваш начальник звучить правильно, кажучи це, однак, більш важливим фактором є захист входів, виходів, переповнення буфера. Недолік цих незмінно є найслабшим ланкою ланцюга з цієї точки зору, незалежно від використовуваного компілятора.

Однак якщо база коду є давньою, і було розпочато роботу з усунення слабких місць використовуваних K&R C, таких як відсутність безпеки типу, незахищені фетти тощо, зважити на питання " Чи можна модернізувати компілятор до сучасного C99 / C11 стандарти все порушують? "

За умови, що існує чіткий шлях до переходу на новіші стандарти С, які можуть викликати побічні ефекти, може бути найкращим чином спробувати вилку старої бази коду, оцінити її та встановити додаткові перевірки типу, перевірки правильності та визначити, чи буде оновлено до новіший компілятор має будь-який вплив на набори вводу / виводу даних.

Тоді ви можете показати це своєму начальнику: " Ось оновлена ​​база коду, що переробляється, більше відповідає стандартам C99 / C11, прийнятим у галузі ... ".

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

EDIT

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

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


Цей же код створений Visual Studio 2008 для цілей Windows, і MSVC ще не підтримує C99 або C11 (я не знаю, чи є новіший MSVC), і я можу створити його на моєму скриньці Linux, використовуючи останню GCC. Тож якби ми просто впустили новіший GCC, він, ймовірно, створив би так само добре, як і раніше.
Кальмарій

@Calmarius дякую за голову вгору, можливо, найкраще буде відредагувати своє запитання, щоб включити коментар, це важливо :) І повинен був бути там; D
t0mm13b

@Calmarius відредагував мою відповідь, яка моя думка щодо нещодавно оновленого питання.
t0mm13b

2
"Може працювати на 16-бітній платформі, швидше за все, оновлення до більш сучасного компілятора може насправді зламати базу коду, я думаю, що стосується архітектури, 32-бітового коду". Я не думаю, що питання полягає у перенесенні коду на нову визначену реалізацією параметри.
Паскаль Куок

Домовились. Це можливо , що виконується вразливість може бути створена помилкою компілятора. Але набагато ймовірніше, що код містить вразливості виконання через такі речі, як переповнення буфера та стека. Отже, коли ви вкладаєте час у те, щоб зробити цю базу коду більш безпечною, вам слід вкласти її в такі дії, як перевірка довжини вхідних рядків, щоб переконатися, що вони не перевищують обмеження вашої програми. Отримати новий компілятор не дуже допоможе. Переписання коду з нуля мовою з рідними об'єктами рядків та масиву допоможе дуже багато. Але ваш начальник за це не заплатить.
О. Джонс

9

Чи може використання старого компілятора C погіршити безпеку компільованої програми?

Звичайно, це може, якщо старий компілятор містить відомі помилки, які, як ви знаєте, впливали б на вашу програму.

Питання в тому, чи не так? Щоб точно знати, вам доведеться прочитати весь журнал змін від вашої версії до теперішньої дати та перевірити кожну помилку, виправлену за ці роки.

Якщо ви не знайдете жодних доказів помилок компілятора, які впливали б на вашу програму, оновлення GCC тільки заради цього здається трохи параноїчним. Вам слід пам’ятати, що новіші версії можуть містити нові помилки, які ще не виявлені. Нещодавно було внесено багато змін із підтримкою GCC 5 та C11.

Незважаючи на це, код, написаний у 80-ті роки, швидше за все, вже заповнений до кінців безпечними отворами та опорою на погано визначену поведінку, незалежно від компілятора. Тут ми говоримо про стандартний C.


6
Я не думаю, що це параноїя; Я думаю, що ОП намагається вигадати причини, щоб переконати свого начальника. Ймовірно, ОП насправді хоче нового компілятора, оскільки вони роблять кращі ASM (включаючи крос-файльну оптимізацію за допомогою LTO), мають більш корисну діагностику / попередження та дозволяють сучасні мовні функції та синтаксис. (наприклад, C11 statatomic).
Пітер Кордес

9

Існує ризик безпеки, коли зловмисний розробник може прокрастися задніми дверима через помилку компілятора. Залежно від кількості відомих помилок у компіляторі, який використовується, задній простір може виглядати більш-менш непомітним (у будь-якому випадку, справа в тому, що код є правильним, навіть якщо він заплутаний, на рівні джерела. Огляд джерел та тести з використанням компілятор, що не баггі, не знайде backdoor, тому що backdoor не існує в цих умовах). Для отримання додаткових балів заперечення зловмисний розробник також може самостійно шукати невідомі помилки компілятора. Знову якість якості камуфляжу буде залежати від вибору знайдених помилок компілятора.

Ця атака проілюстрована на програмному судо в цій статті . bcrypt написав чудове спостереження за міні-версіями Javascript .

Крім цього занепокоєння, еволюція компіляторів була використовувати невизначений поведінка більш і більш і більш агресивно, так що старий C код , який був написаний в дусі доброї волі буде на самому ділі більш безпечним скомпільовано з компілятором від часу, або складеного на -O0 (але деякі нові програмні оптимізації, що експлуатують UB , вводяться в нових версіях компіляторів навіть при -O0 ).


7

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


6

Ще один аспект, який слід турбувати - це розробка нового коду .

Старі компілятори можуть мати різні поведінки для деяких мовних особливостей, ніж те, що стандартизується та очікується програмістом. Ця невідповідність може уповільнити розвиток і ввести непомітні помилки, які можна експлуатувати.

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


5

Ні

Причина проста: старий компілятор може мати старі помилки та подробиці, але новий компілятор матиме нові помилки та подвиги.

Ви не "виправляєте" жодних помилок, перейшовши на новий компілятор. Ваша комутація старих помилок і подвигів для нових помилок і подвигів.


3
Це здається дуже спрощеним: новий компілятор може мати свої слабкі сторони, але я б очікував, що їх буде менше, ніж у старому компіляторі, і, швидше за все, виявляться кілька вразливості коду, які стали відомі з того часу.
PJTraill

Але новий компілятор може мати невідомі нові слабкі сторони. Сам компілятор не є ризиком безпеки, який потребує оновлення. Ви не зменшуєте площу поверхні. Ви торгуєте відомим набором питань для невідомого набору.
coteyr

Інструменти, які допомагають знайти помилки, значно покращилися з ранніх днів GCC, і ці інструменти (статичний аналіз, інструментальний динамічний аналіз коду / дезінсератор, пуховики тощо) також застосовувались до коду компілятора, щоб покращити якість. Набагато складніше було знайти всі класи помилок в епоху GCC 2. Порівняння помилок компілятора по відношенню до версій - див. Сторінку 7: cs.utah.edu/~regehr/papers/pldi11-preprint.pdf GCC 4.5 та LLVM 2.8 (остання при публікації) мають найменшу кількість помилок від плавлення.
Jetski S-type

2

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


0

Ваше питання складається з двох частин:

  • Явне: "Чи більший ризик використання старого компілятора" (більш-менш, як у вашому заголовку)
  • Послідовність: "Як я можу переконати управління оновити"

Можливо, ви можете відповісти на обидва, знайшовши експлуатований недолік у вашій існуючій кодовій базі та показавши, що новіший компілятор виявив би це. Звичайно, ваше керівництво може сказати, "ви виявили це зі старим компілятором", але ви можете зазначити, що це коштувало значних зусиль. Або ви запускаєте його через новий компілятор, щоб знайти вразливість, а потім експлуатуйте його, якщо вам вдається / дозволяється компілювати код з новим компілятором. Ви можете отримати допомогу від доброзичливого хакера, але це залежить від довіри до них та можливості / дозволу показати їм код (та використовувати новий компілятор).

Але якщо ваша система не піддається впливу хакерів, можливо, вас більше зацікавить, чи покращить ефективність оновлення компілятора: Аналіз коду MSVS 2013 досить часто виявляє потенційні помилки набагато швидше, ніж MSVS 2010, і він більш-менш підтримує C99 / C11 - не впевнений, чи це офіційно, але декларації можуть слідувати твердженням, а ви можете оголошувати змінні в for-loops.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.