Предотвратить ненадежный код от кражи контроля над моим приложением через переполнение стека? - PullRequest
0 голосов
/ 21 ноября 2018

Я думаю о написании библиотеки JIT, которая компилирует и выполняет ненадежный код в Windows, Mac и Linux.Язык, на котором написан ненадежный код, является «безопасным» в том смысле, что: массивы проверяются на привязку, невозможно иметь указатели на недоступную память и нет возможности совершать системные вызовы.Кроме того, пространство стека, используемое каждой функцией ненадежного кода, фиксируется во время компиляции (т. Е. Нет массивов переменной длины в стиле alloca() или C).

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

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

Но, очевидно, если функция выделяет большой объем стековой памяти (например, путем объявления большого массива настек), можно «перепрыгнуть» через страницу охраны.Таким образом, тщательно продуманный код может быть переполнен стеком, не вызывая ошибки сегментации.Это означает, что можно было бы создать ненадежный код для выделения достаточного количества стековой памяти, так что моя библиотека JIT скомпилирует его в машинный код, который переходит через защитную страницу.Такой вредоносный код может совершать плохие действия, такие как: перезапись данных из остальной части приложения, чтобы при возврате кода JITted в приложение приложение считывало измененные данные и выполняло действия, для которых оно не предназначалось.делать.Это означает, что вредоносный код фактически получил контроль над всем приложением (и мог бы делать все, что было разрешено приложению).

Как правильно определить переполнение стека?(либо сбой всей программы, либо возврат управления во время выполнения JIT, чтобы я мог с ним справиться)?

Я мог бы придумать два возможных пути:

  • Запросиз ОС оставшееся пространство стека, и проверьте его в прологе каждой функции.Если стекового пространства недостаточно, его можно вызвать для вызова abort().Он может быть запрошен для Linux, как этот ответ , и есть возможность и для других ОС.
  • Проверьте необходимое пространство стека в прологе каждой функции.Это позволит получить доступ к странице защиты, если не хватает места в стеке.Это дело для WAVM .
...