Я хотел бы создать предварительный процессор/компилятор C, который позволяет собирать функции из локальных и онлайн-источников. то есть:
#fetch MP3FileBuilder http://scripts.com/MP3Builder.gz
#fetch IpodDeviceReader http://apple.com/modules/MP3Builder.gz
void mymodule_main() {
MP3FileBuilder(&some_data);
}
Это легкая часть.
Жесткая часть Мне нужен надежный способ "песочницы" импортированного кода из прямого или неограниченного доступа к дисковым или системным ресурсам (включая выделение памяти и стек). Я хочу, чтобы безопасно запускать небольшие фрагменты ненадежного C-кода (модулей) без накладных расходов на их размещение в отдельном процессе, VM или интерпретаторе (отдельный поток был бы приемлемым, хотя).
ПОТРЕБНОСТИ
- Мне нужно поставить квоты на доступ к данным и ресурсам, включая время процессора.
- Я заблокирую прямой доступ к стандартным библиотекам
- Я хочу остановить вредоносный код, который создает бесконечную рекурсию.
- Я хочу ограничить статическое и динамическое распределение конкретными пределами
- Я хочу поймать все исключения, которые модуль может поднять (например, делить на 0).
- Модули могут взаимодействовать только с другими модулями через интерфейсы ядра.
- Модули могут взаимодействовать только с системой (I/O и т.д.) через интерфейсы ядра.
- Модули должны разрешать операции бит, математику, массивы, перечисления, петли и ветвление.
- Модули не могут использовать ASM
- Я хочу ограничить доступ указателей и массивов к памяти, зарезервированной для модуля (через пользовательский safe_malloc())
- Должен поддерживать ANSI C или подмножество (см. ниже)
- Система должна быть легкой и кросс-платформенной (включая встроенные системы).
- Система должна быть совместима с GPL или LGPL.
Я рад согласиться на подмножество C. Мне не нужны такие вещи, как шаблоны или классы. Меня в первую очередь интересуют то, что языки высокого уровня не так хорошо работают, как быстрые математические операции, операции с битами, а также поиск и обработка двоичных данных.
не намерение использовать существующий код C без изменений для создания модуля. Цель состоит в том, что модули должны будут соответствовать набору правил и ограничений, предназначенным для ограничения модуля базовыми логическими и трансформационными операциями (например, например, для транскода или сжатия).
Теоретический вклад в такой компилятор/предварительный процессор будет представлять собой один файл ANSI C (или безопасное подмножество) с функцией module_main, NO включает в себя или предпроцессорные директивы, без ASM, он будет разрешать циклы, ветвление, функцию вызовы, математические указатели (ограниченные диапазоном, выделенным модулю), бит-сдвиг, битподы, приведения, перечисления, массивы, ints, float, strings и maths. Все остальное необязательно.
ПРИМЕР РЕАЛИЗАЦИИ
Вот фрагмент псевдокода, чтобы объяснить это лучше. Здесь модуль превышает его квоту выделения памяти, а также создает бесконечную рекурсию.
buffer* transcodeToAVI_main( &in_buffer ) {
int buffer[1000000000]; // allocation exceeding quota
while(true) {} // infinite loop
return buffer;
}
Здесь представлена преобразованная версия, в которой наш препроцессор добавил точки наблюдения для проверки использования и рекурсии памяти и завернул все это в обработчик исключений.
buffer* transcodeToAVI_main( &in_buffer ) {
try {
core_funcStart(__FILE__,__FUNC__); // tell core we're executing this function
buffer = core_newArray(1000000000, __FILE__, __FUNC__); // memory allocation from quota
while(true) {
core_checkLoop(__FILE__, __FUNC__, __LINE__) && break; // break loop on recursion limit
}
core_moduleEnd(__FILE__,__FUNC__);
} catch {
core_exceptionHandler(__FILE__, __FUNC__);
}
return buffer;
}
Я понимаю, что выполнение этих проверок влияет на производительность модуля, но я подозреваю, что он все же будет превосходить языки высокого уровня или виртуальные языки для задач, которые он предназначен для решения. Я не пытаюсь остановить модули, делающие опасные вещи прямо, я просто пытаюсь заставить эти опасные вещи проходить контролируемым образом (например, через обратную связь с пользователями). т.е.: "Модуль X превысил его распределение памяти, продолжить или прервать?".
UPDATE
Самое лучшее, что я получил до сих пор, - использовать пользовательский компилятор (как взломанный TCC) с проверкой границ, а также некоторые пользовательские функции и код цикла, чтобы поймать рекурсии. Мне все равно хотелось бы услышать мысли о том, что еще мне нужно проверить или какие решения есть там. Я полагаю, что удаление ASM и контрольных указателей перед использованием решает много проблем, выраженных в предыдущих ответах ниже. Я добавил щедрость, чтобы вырвать еще несколько отзывов из сообщества SO.
За щедрость, которую я ищу:
- Подробная информация о потенциальных эксплойтах против теоретической системы, определенной выше
- Возможная оптимизация по проверке указателей при каждом доступе
- Экспериментальные реализации с открытым исходным кодом понятий (например, Google Native Client)
- Решения, поддерживающие широкий диапазон ОС и устройств (без решений на базе ОС/аппаратных средств)
- Решения, поддерживающие большинство операций C, или даже С++ (если это возможно)
Дополнительный кредит за метод, который может работать с GCC (т.е. предварительный процессор или небольшой патч GCC).
Я также рассмотрю всех, кто может окончательно доказать, что я пытаюсь сделать, вообще нельзя. Вы должны быть довольно убедительными, хотя ни одно из возражений до сих пор не прибило технических аспектов того, почему они считают это невозможным. В защиту тех, кто сказал, что этот вопрос не был первоначально поставлен как способ безопасного запуска С++. Я теперь уменьшил требование к ограниченному подмножеству C.
Мое понимание C можно классифицировать как "промежуточное", мое понимание аппаратного обеспечения ПК - это, возможно, шаг ниже "продвинутый". Постарайтесь направить свои ответы на этот уровень, если сможете. Поскольку я не эксперт по C, я буду во многом основываться на ответах, полученных на ответ, а также на то, насколько близко ответ отвечает моим требованиям. Вы можете помочь, предоставив достаточные доказательства для ваших требований (респондентов) и путем голосования (все остальные). Я назначу ответ, как только обратный отсчет щедрот достигнет 6 часов.
Наконец, я считаю, что решение этой проблемы станет важным шагом на пути к поддержанию актуальности C во все более сетевом и параноидальном мире. По мере того, как другие языки значительно сокращают разрыв, а вычислительная мощность возрастает, будет сложнее и сложнее обосновать добавленный риск развития C (как сейчас с ASM). Я считаю, что ваши ответы будут иметь гораздо большее значение, чем забивание нескольких точек SO, поэтому, пожалуйста, внесите свой вклад, даже если истечет срок действия.