Полезно ли использование канареек для bss или разделов данных для обнаружения переполнения / разрушения? - PullRequest
0 голосов
/ 28 января 2020

В нашей встроенной системе на основе G CC C мы используем опции -ffunction-sections и -fdata-sections, чтобы позволить компоновщику при связывании конечного исполняемого файла удалять неиспользуемые (не имеющие ссылок) разделы. Это хорошо работает с годами.

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

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

Одна из идей, которую мы имеем, заключается в размещении канареек между каждым разделом bss и разделом данных - каждый из которых представляет точно один символ (из-за -fdata-sections). Как компилятор делает для стеков функций, когда активированы Stack-Smashing и StackProtection. Проверять эти канареек можно с хоста, читая адреса канареек «время от времени».

Кажется, что изменяют скрипт компоновщика (помещая раздел вручную и добавляя между ними слово канареек) кажется выполнимым, но имеет ли это смысл?

Есть ли в дикой природе проект или статья? Используя мои ключевые слова, я ничего не смог найти.

1 Ответ

2 голосов
/ 28 января 2020

Канарейки в основном полезны для стека, так как он расширяется и сворачивается вне прямого контроля программиста. Вещи, которые вы имеете в data / bss, не ведут себя так. Либо они являются постоянными c переменными, либо, если они являются буферами, они должны соответствовать их фиксированному размеру, который должен быть проверен с помощью защитного программирования на месте с помощью алгоритма, а не неортодоксальных трюков.

Также Канарские стеки используются специально в основанных на RAM системах типа P C, которые не знают лучшего способа. Во встроенных системах они не очень значимы. Вместо этого вы можете сделать несколько полезных вещей:

  • Память отображает стек так, чтобы он вырос в область памяти, в которой при записи произойдет аппаратное исключение. Как, например, если у вашего MCU есть возможность отделить исполняемую память от памяти данных и выдавать исключения, если вы пытаетесь выполнить код в области данных или выполнить запись в исполняемую область.
  • Убедитесь, что все в вашей программе при работе с буферами выполняются их проверки ошибок, а не запись за пределы. Инструменты анализа Stati c, как правило, хороши для выявления недопустимых ошибок. Даже некоторые компиляторы могут сделать это.
  • Добавить много защитного программирования с утверждениями stati c. Проверьте размеры структур, буферов и c во время компиляции, это бесплатно.
  • Защитное программирование во время выполнения. Например, if(x==good) {...} else if(x == bad) {... } отсутствует else. И switch(x) case A: { ... } отсутствует default. "Но это не может go там в теории!" Нет, но на практике, когда вы получаете убегающий код, вызванный ошибками (очень вероятно), сохранением данных fla sh (вероятность 100%) или влиянием EMI на RAM (весьма маловероятно).
  • И и так далее .
...