Вредная C Проверка исходного файла? - PullRequest
6 голосов
/ 25 июля 2011

Есть ли способ программно проверить, является ли один C source file потенциально вредным?

I знает , что никакая проверка не даст 100% точности -но я заинтересован по крайней мере сделать некоторые базовые проверки, которые поднимут красный флаг, если будут найдены некоторые выражения / ключевые слова.Любые идеи о том, что искать?

Примечание: файлы, которые я буду проверять, имеют относительно небольшой размер (всего несколько сотен строк), реализуя функции численного анализа, которые все работают в памяти .Никакие внешние библиотеки (кроме math.h) не должны использоваться в коде.Кроме того, ввод / вывод не должен использоваться (функции будут выполняться с массивами в памяти).

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

Примечание: , поскольку я не ожидаю ввода-вывода, если код выполняет ввод-вывод - считаетсявреден .

Ответы [ 3 ]

8 голосов
/ 25 июля 2011

Да, существуют программные способы обнаружения условий, которые вас беспокоят.

Мне кажется, в идеале вы хотите, чтобы инструмент статического анализа проверял, что предварительно обработанная версия кода:

  1. Не вызывает никаких функций, кроме тех, которые он определяет, и функций, не относящихся к вводу / выводу, в стандартной библиотеке,
  2. Ничего плохого не делает с указателями.

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

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

Цель проверки на наличие плохих вещей с помощью указателей состоит в том, чтобы они не злоупотребляли указателями для изготовления вредоносного кода и передачи ему контроля. Во-первых, это означает, что «нет указателей на целочисленные значения», потому что вы не знаете, где находится int: -}

Для проверки «кто делает вызов» необходимо проанализировать код и имя / тип, определить каждый символ, а затем проверить сайты вызовов, чтобы увидеть, куда они направляются. Если вы разрешите указатели / указатели функций, вам потребуется полный анализ точек.

Одна из компаний-разработчиков стандартных статических анализаторов (Coverity, Klocwork), вероятно, предоставляет какой-то метод ограничения функций, которые может вызывать блок кода. Если это не сработает, вам придется воспользоваться более общими механизмами анализа, такими как DMS Software Reengineering Toolkit с C Front End . DMS предоставляет настраиваемый механизм для создания произвольных статических анализаторов для описания языка, предоставляемого ему в качестве внешнего интерфейса. DMS может быть настроен на выполнение именно теста 1), включая этап предварительной обработки; он также имеет полные точки и функциональные точки для анализаторов, которые можно использовать для проверки точек.

Для 2) «не использует указатели злонамеренно», опять же, стандартные компании-разработчики статического анализа предоставляют некоторую проверку указателей. Однако здесь у них гораздо более сложная проблема, поскольку они статически пытаются рассуждать о машине Тьюринга. Их решение - либо пропустить дела, либо сообщить о ложных срабатываниях. Наш инструмент CheckPointer представляет собой динамический анализ, то есть он отслеживает код во время его выполнения и, если есть какая-либо попытка злоупотребить указателем, CheckPointer немедленно сообщит о месте нарушения. О, да, CheckPointer вне закона переводит целочисленные значения в указатели: -} Таким образом, CheckPointer не будет предоставлять статическую диагностику «этот код может обмануть», но вы получите диагностику, если он действительно попытается обмануть. У CheckPointer довольно высокие накладные расходы (все эти проверки стоят чего-то), поэтому вы, вероятно, захотите некоторое время запустить свой код с ним, чтобы обрести уверенность в том, что ничего плохого не произойдет, и затем прекратите его использовать.

РЕДАКТИРОВАТЬ: Другой плакат говорит: Вы не можете ничего сделать с перезаписью буферов для статически определенных буферов . CheckPointer будет выполнять эти тесты и многое другое.

3 голосов
/ 25 июля 2011

Если вы хотите убедиться, что он не вызывает ничего недопустимого, скомпилируйте кусок кода и проверьте, на что он ссылается (скажем, через nm). Поскольку вы зациклены на этом «программным» методом, просто используйте python / perl / bash для компиляции, а затем просканируйте список имен объектного файла.

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

Вы также можете скомпилировать и связать рассматриваемый C-файл с драйвером, который будет передавать ему типичные данные при работе в valgrind, что может помочь обнаружить плохо или злонамеренно написанный код.

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

EDIT : пример использования nm:

Создание функции определения фрагмента C foo, которая вызывает fopen:

#include <stdio.h>
foo() {
   FILE *fp = fopen("/etc/passwd", "r");
}

Скомпилируйте с -c, а затем посмотрите на получившийся объектный файл:

$ gcc -c foo.c
$ nm foo.o
0000000000000000 T foo
                 U fopen

Здесь вы увидите, что в объектном файле foo.o есть два символа. Определено одно, foo, название подпрограммы, которую мы написали. И один не определен, fopen, который будет связан с его определением, когда объектный файл будет связан вместе с другими C-файлами и необходимыми библиотеками. Используя этот метод, вы можете сразу увидеть, ссылается ли скомпилированный объект на что-либо, находящееся за пределами его собственного определения, и по вашим правилам он может считаться «плохим».

0 голосов
/ 25 июля 2011

Вы могли бы сделать некоторые очевидные проверки для «плохих» вызовов функций, таких как сетевой ввод-вывод или сборочные блоки. Кроме того, я не могу придумать ничего, что вы можете сделать только с C-файлом.

Учитывая природу C, вам просто нужно будет скомпилировать, чтобы даже начать. Макросы и т.п. делают статический анализ кода на C довольно сложным.

...