Как предотвратить вызов API в исходном коде? - PullRequest
4 голосов
/ 30 июня 2011

Чтобы разработать онлайн-судью для соревнования ACM , мы должны предотвратить вызов некоторых API в исходном коде, представленном пользователями.Например, в исходном коде нельзя вызывать shutdown() или socket().Если исходный код вызывает API, мы должны прекратить его компиляцию или генерировать ошибки во время компиляции, или генерировать ошибки во время работы.

Я понятия не имею, как это сделать в Linux или Windows;ребята, вы можете дать мне несколько советов?

Ответы [ 7 ]

2 голосов
/ 30 июня 2011

Вам необходимо использовать изолированную программную среду ядра, например, "user-mode linux" или "functions".

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

.
2 голосов
/ 30 июня 2011

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

Второе: как вы уже предлагали, вы можете использовать LD_PRELOAD для ссылки на ограниченную библиотеку. Другим вариантом, который также работает против некоторых других запрещенных вещей, таких как защита, является песочница: настройте среду chroot, в которой вы просто устанавливаете эти запрещенные библиотеки, поэтому доступ к запрещенным вещам невозможен.

0 голосов
/ 16 сентября 2012

Фильтрация исходного кода недостаточна.Даже если исходный код не вызывает API, он может использовать трюки для его вызова.Например, простой фильтр на основе регулярных выражений может быть побежден путем вставки токена.И это только на уровне исходного кода;когда вы начинаете думать о машинном коде, есть много других возможностей, от простой встроенной сборки до программирования с возвратом , и это можно сделать способом, который трудно увидеть, глядя наисходный код, как показано в Underhanded C Contest .

Все API в конечном итоге сводятся к API ядра, поскольку программист может просто скопировать реализацию API в противном случае.Есть AFAIK только два безопасных способа предотвратить вызов API ядра: либо отфильтровать его в ядре, либо статически доказать, что код не может вызвать ядро ​​напрямую.Другие способы, такие как LD_PRELOAD, можно обойти.Обойти LD_PRELOAD легко;просто сделайте системный вызов напрямую.

Чтобы отфильтровать API в ядре, самый последний способ - использовать seccomp filters , который позволяет ограничивать системные вызовы и их параметры.С его помощью вы можете легко запретить процессу, например, когда-либо вызывать системные вызовы shutdown и socket.Другие механизмы (пространства имен, cgroups, chroot и т. Д.) Могут быть использованы для добавления других видов ограничений поверх фильтра.

Альтернативный подход статистической проверки кода безопасен, используется в Google NativeКлиент .Он ограничивает сгенерированный ассемблерный код способами, позволяющими получить простые доказательства того, что поток выполнения не может покинуть «песочницу», за исключением нескольких четко определенных способов.В качестве примера правил такого рода никакие инструкции не могут пересекать 32-байтовую границу, все цели перехода выровнены по 32-байтовой границе, а косвенные переходы разрешены только через пару инструкций, которые маскируют младшие биты целиадрес перед прыжком, поэтому невозможно перейти к середине инструкции.

0 голосов
/ 30 июня 2011

Имейте в виду, что вам не нужна библиотека сокетов для доступа к сети, вы можете сделать это с помощью open () read () и write ().Так что вам, вероятно, нужна какая-то песочница, а не просто ограничения на то, что разрешено в коде.

0 голосов
/ 30 июня 2011

Ответ для Linux:

nm -D _the_compiled_binary_ | grep ' U '

перечислит все динамические символы, используемые (вызываемые) двоичным файлом.

0 голосов
/ 30 июня 2011
#define verboten_api(a1, a2, a3) you may not use this verboten API

Убедитесь, что они должны использовать заголовок, содержащий verboten API.

GNU предоставляет атрибут «устарел».Из руководства GCC 4.6.1:

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

int old_fn () __attribute__ ((deprecated));
int old_fn ();
int (*fn_ptr)() = old_fn;

приводит к появлению предупреждения в строке 3, но не в строке 2. Необязательный аргумент msg, который должен быть строкой, будет напечатан в предупреждении, если он присутствует.Устаревший атрибут также можно использовать для переменных и типов (см. Раздел 6.36 [Атрибуты переменных], стр. 341, см. Раздел 6.37 [Типы атрибутов], стр. 350).

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

Это проверки во время компиляции, а не проверки во время выполнения.Они, вероятно, также навязчивы, если только вы не хотите взломать используемые системные заголовки.Кроме того, если конкуренты не используют системный заголовок, они могут сойтись с ним.

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

int verboten_api(int x, int y, char *z)
{
    assert("function verboten_api() called" == 0);
    return -1;
}

Свяжите тестовые программы с этой библиотекой.

0 голосов
/ 30 июня 2011

Сначала вы должны определить, к какому API вы не хотите получать доступ. Я думаю, что, вероятно, легче выполнить статический анализ кода и вызвать ошибку, если произойдет какое-то нежелательное #includes.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...