Ticket #111: omindex-limit-filter-resource-usage.patch

File omindex-limit-filter-resource-usage.patch, 3.8 KB (added by Olly Betts, 17 years ago)

First attempt at a patch

  • runfilter.cc

     
    1919
    2020#include <config.h>
    2121
     22#include <iostream>
    2223#include <string>
    2324
     25#include <limits.h>
     26#include "safeerrno.h"
    2427#include <sys/types.h>
    2528#include <stdio.h>
    2629#include "safefcntl.h"
     30
     31#include <sys/time.h>
     32#include <sys/resource.h>
    2733#ifdef HAVE_SYS_WAIT_H
    2834# include <sys/wait.h>
    2935#endif
     36#include <sys/socket.h>
     37#include "safeunistd.h"
    3038
    3139#include "runfilter.h"
    3240
     
    5058stdout_to_string(const string &cmd)
    5159{
    5260    string out;
     61#ifdef HAVE_FORK
     62    // We want to be able to get the exit status of the child process.
     63    signal(SIGCHLD, SIG_DFL);
     64
     65    int fds[2];
     66    if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) < 0)
     67        throw ReadError();
     68
     69    pid_t child = fork();
     70    if (child == 0) {
     71        // We're the child process.
     72
     73        // Close the parent's side of the socket pair.
     74        close(fds[0]);
     75
     76        // Connect stdout to our side of the socket pair.
     77        dup2(fds[1], 1);
     78
     79        // Limit CPU time to 300 seconds (5 minutes).
     80        struct rlimit cpu_limit = { 300, RLIM_INFINITY } ;
     81        setrlimit(RLIMIT_CPU, &cpu_limit);
     82
     83        // Limit process data to 7/8 of free physical memory.
     84        static long pagesize = 0;
     85        if (pagesize == 0) pagesize = sysconf(_SC_PAGESIZE);
     86
     87        if (pagesize > 0) {
     88            long mem = sysconf(_SC_AVPHYS_PAGES);
     89            if (mem > 0) {
     90                if (mem >= LONG_MAX / pagesize) {
     91                    mem = LONG_MAX;
     92                } else {
     93                    mem *= pagesize;
     94                }
     95
     96                mem = (mem / 8) * 7;
     97                struct rlimit ram_limit = { mem, RLIM_INFINITY } ;
     98                setrlimit(RLIMIT_DATA, &ram_limit);
     99            }
     100        }
     101
     102        execl("/bin/sh", "/bin/sh", "-c", cmd.c_str(), (void*)NULL);
     103        _exit(-1);
     104    }
     105
     106    // We're the parent process.
     107
     108    // Close the child's side of the socket pair.
     109    close(fds[1]);
     110    if (child == -1) {
     111        // fork() failed.
     112        close(fds[0]);
     113        throw ReadError();
     114    }
     115
     116    int fd = fds[0];
     117
     118    while (true) {
     119        char buf[4096];
     120        ssize_t res = read(fd, buf, sizeof(buf));
     121        if (res == 0) break;
     122        if (res == -1) {
     123            if (errno != EINTR) {
     124                close(fd);
     125                int status;
     126                (void)waitpid(child, &status, 0);
     127                throw ReadError();
     128            }
     129        }
     130        out.append(buf, res);
     131    }
     132
     133    close(fd);
     134    int status;
     135    if (waitpid(child, &status, 0) == -1) {
     136        throw ReadError();
     137    }
     138#else
    53139    FILE * fh = popen(cmd.c_str(), "r");
    54140    if (fh == NULL) throw ReadError();
    55141    while (!feof(fh)) {
     
    62148        out.append(buf, len);
    63149    }
    64150    int status = pclose(fh);
     151#endif
     152
    65153    if (status != 0) {
    66154        if (WIFEXITED(status) && WEXITSTATUS(status) == 127) {
    67155            throw NoSuchFilter();
    68156        }
     157#ifdef SIGXCPU
     158        if (WIFSIGNALED(status) && WTERMSIG(status) == SIGXCPU) {
     159            cerr << "Filter process consumed too much CPU time" << endl;
     160        }
     161#endif
    69162        throw ReadError();
    70163    }
    71164    return out;
  • configure.ac

     
    7474AC_FUNC_STRFTIME
    7575AC_CHECK_FUNCS(gettimeofday ftime)
    7676
    77 dnl See if ftime returns void (as it does on mingw)
     77dnl See if ftime() returns void (as it does on mingw).
    7878if test $ac_cv_func_ftime = yes ; then
    7979  AC_TRY_COMPILE([#include <sys/timeb.h>],
    8080    [struct timeb tp; int i = ftime(&tp);],
     
    8282    AC_DEFINE(FTIME_RETURNS_VOID, 1, [Define if ftime returns void]))
    8383fi
    8484
    85 dnl Check for lstat (not available under mingw for example).
     85dnl Check for lstat() (not available under mingw for example).
    8686AC_CHECK_FUNCS(lstat)
    8787
    88 dnl Add in portable replacement for mkdtemp on platforms which lack it.
     88dnl omindex uses fork() under UNIX.
     89AC_CHECK_FUNCS(fork)
     90
     91dnl Add in portable replacement for mkdtemp() on platforms which lack it.
    8992AC_CHECK_FUNCS(mkdtemp)
    9093AM_CONDITIONAL(NEED_MKDTEMP, [test yes != "$ac_cv_func_mkdtemp"])
    9194