2011-01-16 4 views
3

Я разрабатываю грейдер для программирования конкурсов. В принципе, грейдер должен запускать программу решения в «изолированном» процессе. Поэтому я хотел бы, чтобы решение не вызывало каких-либо вредоносных системных вызовов (таких как system(), fork() и т. Д.). Могу ли я использовать ptrace() для достижения этого?UNIX ptrace() блокирует системные вызовы ребенка

ответ

1

Я думаю, что есть 2 возможных решения:

  1. Использование механизма LD_PRELOAD создать «подкладку», чтобы заменить системные вызовы вы хотите остановить.
  2. Используйте setrlimit(), чтобы ограничить процесс вызова. К сожалению, эти ограничения кажутся для каждого пользователя, а не для каждого процесса, что делает вычисление правильного значения очень сложным.

EDIT: У меня есть первый вариант работы и включил в него необходимый код. Сборка бинарных файлов с помощью make all, а затем проверить с make runtests:

$ make all 
gcc -fPIC -shared -Wl,-soname,libmy.so.1 -o libmy.so.1.0 lib.c 
ln -sf libmy.so.1.0 libmy.so.1 
ln -sf libmy.so.1 libmy.so 
gcc -o test test.c 

$ make runtests 
Without LD_PRELOAD: 
./test 
in child: retval=9273 
in parent: retval=0 
With LD_PRELOAD: 
LD_PRELOAD=./libmy.so ./test 
libmy.so fork! 
fork error: error=Operation not permitted (1) 

Makefile:

all: libs test 

runtests: 
    @echo Without LD_PRELOAD: 
    ./test 
    @echo With LD_PRELOAD: 
    LD_PRELOAD=./libmy.so ./test 


libs: lib.c 
    gcc -fPIC -shared -Wl,-soname,libmy.so.1 -o libmy.so.1.0 lib.c 
    ln -sf libmy.so.1.0 libmy.so.1 
    ln -sf libmy.so.1 libmy.so 

test: test.c 
    gcc -o test test.c 

clean: 
    rm -f test libmy.so.1.0 libmy.so.1 libmy.so lib.o 

lib.c:

#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 

pid_t fork() 
{ 
    printf("libmy.so fork!\n"); 
    errno = EPERM; 
    return (pid_t)-1; 
} 

test.c:

#include <stdio.h> 
#include <string.h> 
#include <errno.h> 

int main(int argc, char **argv) 
{ 
    int retval = fork(); 
    if (retval == 0) 
     printf("in parent: retval=%d\n", retval); 
    else if (retval > 0) 
     printf("in child: retval=%d\n", retval); 
    else 
     printf("fork error: error=%s (%d)\n", strerror(errno), errno); 
    return 0; 
} 
+0

Спасибо, но можете ли вы объяснить немного больше о «механизме LD_PRELOAD»? – fushar

+0

Если вы задали переменную среды $ LD_PRELOAD, указывающую на общую библиотеку, тогда эта библиотека будет использоваться по сравнению с теми, которые установлены в исполняемом файле. Я не знаю, работает ли он для функций системного уровня или нет. – trojanfoe

+0

Хорошо, тогда второй вариант: какой ресурс в setrlimit() мне нужно установить для предотвращения системных вызовов? – fushar

0

Да ты можешь использовать ptrace() для блокировки определенных системных вызовов с использованием параметра PTRACE_SYSCALL. Вот проект с использованием этой функции:

https://github.com/t00sh/p-sandbox/blob/master/p-sandbox.c

Если вы нацелены только на Linux, я хотел бы предложить Seccomp вместо этого, что более быстрый метод, в белый список/черный список некоторых системных вызовов или ограничить свои аргументы.

Альтернативой будет Native Client Google. Эти проекты обеспечивают кросс-платформенную реализацию изолированной программной среды приложения.

Вы также можете запускать приложения в качестве непривилегированного пользователя в контейнере, таком как докер или LXC, для ограничения ущерба.

Использование только LD_PRELOAD небезопасно, так как исполняемый файл может поставляться со своей реализацией и отключать основной libc.

Смежные вопросы