2014-02-09 2 views
0

Есть ли программный способ ограничения продолжительности, использования памяти и использования как менее привилегированного пользователя для выполнения программы Linux в C/C++ или Ruby?Как ограничить время выполнения программы, использование памяти и как конкретный пользователь в Linux

поскольку система или `` не могут этого сделать.

sprintf(cmd_str,"/tmp/pro-%d </tmp/in.txt> /tmp-%d.txt",id,id); 
system(cmd_str); // in C 

`/tmp/pro-#{id} </tmp/in.txt> /tmp/out-#{id}.txt` // in Ruby 

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

ответ

1

Чтобы ограничить память, вы должны использовать системный вызов setrlimit (Process::RLIMIT_AS). Чтобы ограничить время выполнения программы, вы можете контролировать общее количество секунд, в течение которых процесс получает процессорное время (так что не учитывается время, затраченное на спящий режим или ожидающий ввода/вывода). Это делается с Process::CPU.

падения привилегий с Process::Sys.setgid следует Process::Sys.setuidпосле установки этих rlimits, но перед вызовом целевого процесса с Process::exec.

Пример целевой программы:

#include <stdio.h> 
#include <stdlib.h> 

#include <unistd.h> 

#define ALLOC_SIZE_1 1024 
#define ALLOC_SIZE_2 (1024 * 1024 * 5) 

int 
main(int argc, char *argv[]) 
{ 
    char *buf; 

    fprintf(stderr, "[+] uid: %d, gid: %d\n", getuid(), getgid()); 

    fprintf(stderr, "[+] trying to allocate %d bytes (should succeed)...\n", ALLOC_SIZE_1); 
    if (NULL == (buf = malloc(ALLOC_SIZE_1))) { 
    fprintf(stderr, "[!] failed!\n"); 
    return -1; 
    } 

    fprintf(stderr, "[+] success.\n"); 
    free(buf); 

    fprintf(stderr, "[+] trying to allocate %d bytes (should fail)...\n", ALLOC_SIZE_2); 
    if (NULL != (buf = malloc(ALLOC_SIZE_2))) { 
    fprintf(stderr, "[!] succeeded! (should have failed.)\n"); 
    return -1; 
    } 

    fprintf(stderr, "[+] ok. now doing infinite loop (should get killed pretty soon)...\n"); 
    for (;;); 

    return 0; 
} 

и сопровождающий Рубин сценарий, чтобы вызвать его (запустить этот сценарий как корень с, например, sudo /tmp/foo.rb):

#!/usr/bin/env ruby 

TARGET_GID = 99 
TARGET_UID = 99 

Process::setrlimit(Process::RLIMIT_AS, 1024 * 1024 * 5) 
Process::setrlimit(Process::RLIMIT_CPU, 3) 

Process::Sys.setgid(TARGET_GID) 
Process::Sys.setuid(TARGET_UID) 

Process::exec('/tmp/test') 

И, наконец, выход работает на моей машине :

$ sudo ./run.rb 
[+] uid: 99, gid: 99 
[+] trying to allocate 1024 bytes (should succeed)... 
[+] success. 
[+] trying to allocate 5242880 bytes (should fail)... 
[+] ok. now doing infinite loop (should get killed pretty soon)... 
$ 
2

seteuid(2) системный вызов; устанавливает эффективный идентификатор пользователя вызывающего процесса.

Ниже рубин пример (см Process::Sys.seteuid)

Process.uid # => 0 
Process.euid # => 0 
Process::Sys.seteuid(1000) # Etc::getpwnam('falsetru').uid == 1000 
Process.uid # => 0 
Process.euid # => 1000 
1

Как @falsetru отмечалось, системный вызов вы хотите запустить, как другой пользователь setrlimit или из командной строки su или sudo.

Если вы хотите ограничить ресурсы, вы хотите использовать системный вызов setrlimit или ulimit из оболочки. Это ограничит использование памяти и т. Д., Но не полную продолжительность выполнения - вам нужно будет отслеживать процесс и kill, если вы этого хотите.

Вы также можете посмотреть nice, чтобы установить его приоритет.