コード例 #1
0
ファイル: safeexec.c プロジェクト: ochko/safeexec
int main (int argc, char **argv, char **envp)
{

  struct rusage usage;

  char **p;
  int status, mem, skipped, memused;
  int tsource, ttarget;
  int v;

  redirect = stderr;
  safe_signal (SIGPIPE, SIG_DFL);

  tsource = time (NULL);
  p = parse (argv);
  if (p == NULL)
    {
      printusage (argv);
      return (EXIT_FAILURE);
    }
  else
    {
      /* Get an unused uid */
      if (profile.minuid != profile.maxuid)
        {
          srand (time (NULL) ^ getpid ());
          profile.minuid += rand () % (profile.maxuid - profile.minuid);
        }

      if (strcmp (usage_file, "/dev/null") != 0)
        {
          redirect = fopen (usage_file, "w");
          chown (usage_file, profile.minuid, getgid());
          chmod (usage_file, 0640);
          if (redirect == NULL)
            error ("Couldn't open usage file\n");
        }

      /* stderr from user program is junk */
      junk = fopen (error_file, "w");
      if (junk == NULL)
        error ("Couldn't open junk file %s\n", error_file);
      if (strcmp (error_file, "/dev/null") != 0)
        {
          chown (error_file, profile.minuid, getgid());
          chmod (error_file, 0640);
        }

      if (setgid (profile.minuid) < 0)
        {
          if (errno == EPERM)
            {
              error ("Couldn't setgid due to permission");
            }
          else
            {
              error (NULL);
            }
        }
      if (setuid (profile.minuid) < 0)
        {
          if (errno == EPERM)
            {
              error ("Couldn't setuid due to permission");
            }
          else
            {
              error (NULL);
            }
        }


      if (getuid () == 0)
        error ("Not changing the uid to an unpriviledged one is a BAD ideia");

      if (signal (SIGALRM, wallclock) == SIG_ERR)
        error ("Couldn't install signal handler");

      if (alarm (profile.clock) != 0)
        error ("Couldn't set alarm");

      /* Fork new process */
      pid = fork ();
      if (pid < 0)
        error (NULL);

      if (pid == 0)
        /* Forked/child process */
        {
          /* Chrooting */
          if (chroot_dir != NULL)
            {
              if (0 != chdir(chroot_dir))
                {
                  kill (getpid (), SIGPIPE);
                  error ("Can not change to chroot dir");
                }
              if (0 != chroot(chroot_dir))
                {
                  kill (getpid (), SIGPIPE);
                  error ("Can not chroot");
                }
            }
          /* Change dir */
          if (run_dir != NULL)
            {
              if (0 != chdir(run_dir))
                {
                  kill (getpid (), SIGPIPE);
                  error ("Cannot change to rundir");
                }
            }

          dup2(fileno(junk), fileno(stderr));

          if (setuid (profile.minuid) < 0)
            error (NULL);

          /* Don't run as root */
          if (getuid () == 0)
            error ("Running as a root is not secure!");

          /* Set priority */
          if (0 != setpriority(PRIO_USER,profile.minuid,NICE_LEVEL))
            {
              kill (getpid (), SIGPIPE);
              error (NULL);
            }

          /* Set resource limits - memory, time etc */
          setlimits(profile);

          /* Execute the program */
          if (execve (*p, p, envp) < 0)
            {
              kill (getpid (), SIGPIPE);
              error (NULL);
            }
        }
      else
        /* Parent process */
        {
          if (setuid (profile.minuid) < 0)
            error (NULL);

          if (getuid () == 0)
            error ("Running as a root is not secure!");

          memusage_init ();

          mark = OK;

          /* Poll every INTERVAL ms and get the maximum   *
           * memory usage, exit when the child terminates */
          mem = 64;
          skipped = 0;
          memused = 0;
          do
            {
              msleep (INTERVAL);
              memused = memusage (pid);
              if (memused > -1)
                {
                  mem = max (mem, memused);
                }
              else
                { /* Can not read memory usage! */
                  skipped++;
                }

              if (skipped > 10)
                { /* process is already finished or something wrong happened */
                  terminate (pid);
                  mark = MLE;
                }

              if (mem > profile.memory)
                {
                  terminate (pid);
                  mark = MLE;
                }

              do
                v = wait4 (pid, &status, WNOHANG | WUNTRACED, &usage);
              //v = wait4 (pid, &status, WNOHANG | WUNTRACED | WCONTINUED | WEXITED, &usage);
              while ((v < 0) && (errno != EINTR));
              if (v < 0)
                error (NULL);
            }
          while (v == 0);

          memusage_close ();

          ttarget = time (NULL);

          if (mark == MLE)
            printstats ("Memory Limit Exceeded\n");
          else if (mark == RTLE)
            printstats ("Time Limit Exceeded\n");
          else
            {
              if (WIFEXITED (status) != 0)
                {
                  if (WEXITSTATUS (status) != 0)
                    printstats ("Command exited with non-zero status (%d)\n",
                                WEXITSTATUS (status));
                  else
                    printstats ("OK\n");
                }
              else
                {
                  if (WIFSIGNALED (status) != 0)
                    {
                      /* Was killed for a TLE (or was it an OLE) */
                      if (WTERMSIG (status) == SIGKILL)
                        mark = TLE;
                      else if (WTERMSIG (status) == SIGXFSZ)
                        mark = OLE;
                      else if (WTERMSIG (status) == SIGHUP)
                        mark = RF;
                      else if (WTERMSIG (status) == SIGPIPE)
                        mark = IE;
                      else
                        printstats ("Command terminated by signal (%d: %s)\n",
                                    WTERMSIG (status),
                                    name (WTERMSIG (status)));
                    }
                  else if (WIFSTOPPED (status) != 0)
                    printstats ("Command terminated by signal (%d: %s)\n",
                                WSTOPSIG (status), name (WSTOPSIG (status)));
                  else
                    printstats ("OK\n");

                  if (mark == TLE)
                    {
                      /* We know the child has terminated at right time(OS did). *
                       * But seing 1.990 as TLE while limit 2.0 is confusing.    *
                       * So here is small adjustment for presentation.           */
                      usage.ru_utime.tv_sec = profile.cpu;
                      usage.ru_utime.tv_usec = 0;
                      printstats ("Time Limit Exceeded\n");
                    }
                  else if (mark == OLE)
                    printstats ("Output Limit Exceeded\n");
                  else if (mark == RTLE)
                    printstats ("Time Limit Exceeded\n");
                  else if (mark == RF)
                    printstats ("Invalid Function\n");
                  else if (mark == IE)
                    printstats ("Internal Error\n");
                }
            }
          printstats ("elapsed time: %d seconds\n", ttarget - tsource);
          printstats ("memory usage: %d kbytes\n", mem);
          printstats ("cpu usage: %0.3f seconds\n",
                      (float) miliseconds (&usage.ru_utime) / 1000.0);
        }
    }
  fclose (redirect);

  return (EXIT_SUCCESS);
}
コード例 #2
0
ファイル: safeexec.c プロジェクト: BastinRobin/safeexec
int main (int argc, char **argv, char **envp)
{
  struct rusage usage;
  char **p;
  int status, mem;
  int tsource, ttarget;
  int v;

  redirect = stderr;
  safe_signal (SIGPIPE, SIG_DFL);

  tsource = time (NULL);
  p = parse (argv);
  if (p == NULL)
    {
      printusage (argv);
      return (EXIT_FAILURE);
    }
  else
    {
      /*
         fprintf (stderr, "profile: \"%s\"\n", limit->name);
         fprintf (stderr, "  cpu=%u\n  mem=%u\n", (unsigned int) limit->cpu,
         (unsigned int) limit->memory);
         fprintf (stderr, "  core=%u\n  stack=%u\n", (unsigned int) limit->core,
         (unsigned int) limit->stack);
         fprintf (stderr, "  fsize=%u\n  nproc=%u\n", (unsigned int) limit->fsize,
         (unsigned int) limit->nproc);
         fprintf (stderr, "  minuid=%u\n  maxuid=%u\n", (unsigned int) limit->minuid,
         (unsigned int) limit->maxuid);
         fprintf (stderr, "  clock=%u\n",
         (unsigned int) limit->clock);
       */

      /* Still missing: get an unused uid from interval */
      if (profile.minuid != profile.maxuid)
        {
          srand (time (NULL) ^ getpid ());
          profile.minuid += rand () % (profile.maxuid - profile.minuid);
        }

      if (setuid (profile.minuid) < 0)
        error (NULL);

      if (strcmp (usage_file, "/dev/null") != 0)
        {
          redirect = fopen (usage_file, "w");
          chmod (usage_file, 0644);
          if (redirect == NULL)
            error ("Couldn't open redirection file\n");
        }

      if (getuid () == 0)
        error ("Not changing the uid to an unpriviledged one is a BAD ideia");

      if (signal (SIGALRM, wallclock) == SIG_ERR)
        error ("Couldn't install signal handler");

      if (alarm (profile.clock) != 0)
        error ("Couldn't set alarm");

      pid = fork ();
      if (pid < 0)
        error (NULL);
      if (pid == 0)
        {
          /* change to chroot dir */
          if (0 != chdir(chroot_dir))
            {
              kill (getpid (), SIGPIPE);
              error ("Cannot change to chroot dir");
            }

          /* chroot to judge dir  */
          if (0 != chroot(chroot_dir))
            {
              kill (getpid (), SIGPIPE);
              error ("Cannot chroot");
            }
          /* change to run dir */
          if (0 != chdir(run_dir))
            {
              kill (getpid (), SIGPIPE);
              error ("Cannot change to rundir");
            }

          if (setuid (profile.minuid) < 0)
            error (NULL);

          if (getuid () == 0)
            error ("Not changing the uid to an unpriviledged one is a BAD ideia");

          /* set priority */
          if (0 != setpriority(PRIO_USER,profile.minuid,NICE_LEVEL))
            {
              kill (getpid (), SIGPIPE);
              error (NULL);
            }

          /* Set Address space limit, 1 mbyte tolerancy (librarys also count!) */
          /*setlimit (RLIMIT_AS, (1024 + limit->memory) * 1024); */
          setlimit (RLIMIT_CORE, profile.core * 1024);
          setlimit (RLIMIT_STACK, profile.stack * 1024);
          setlimit (RLIMIT_FSIZE, profile.fsize * 1024);
          setlimit (RLIMIT_NPROC, profile.nproc);
          setlimit (RLIMIT_CPU, profile.cpu);

          /* Execute the program */
          if (execve (*p, p, envp) < 0)
            {
              kill (getpid (), SIGPIPE);
              error (NULL);
            }
        }
      else
        {
          if (setuid (profile.minuid) < 0)
            error (NULL);

          if (getuid () == 0)
            error ("Not changing the uid to an unpriviledged one is a BAD ideia");

          mark = OK;

          /* Poll at INTERVAL ms and determine the maximum *
           * memory usage,  exit when the child terminates */

          mem = 64;
          do
            {
              msleep (INTERVAL);
              mem = max (mem, memusage (pid));
              if (mem > profile.memory)
                {
                  terminate (pid);
                  mark = MLE;
                }
              do
                v = wait4 (pid, &status, WNOHANG | WUNTRACED, &usage);
              while ((v < 0) && (errno != EINTR));
              if (v < 0)
                error (NULL);
            }
          while (v == 0);

          ttarget = time (NULL);

          if (mark == MLE)
            printstats ("Memory Limit Exceeded\n");
          else if (mark == RTLE)
            printstats ("Time Limit Exceeded\n");
          else
            {
              if (WIFEXITED (status) != 0)
                {
                  if (WEXITSTATUS (status) != 0)
                    printstats ("Command exited with non-zero status (%d)\n",
                                WEXITSTATUS (status));
                  else
                    printstats ("OK\n");
                }
              else
                {
                  if (WIFSIGNALED (status) != 0)
                    {
                      /* Was killed for a TLE (or was it an OLE) */
                      if (WTERMSIG (status) == SIGKILL)
                        mark = TLE;
                      else if (WTERMSIG (status) == SIGXFSZ)
                        mark = OLE;
                      else if (WTERMSIG (status) == SIGHUP)
                        mark = RF;
                      else if (WTERMSIG (status) == SIGPIPE)
                        mark = IE;
                      else
                        printstats ("Command terminated by signal (%d: %s)\n",
                                    WTERMSIG (status),
                                    name (WTERMSIG (status)));
                    }
                  else if (WIFSTOPPED (status) != 0)
                    printstats ("Command terminated by signal (%d: %s)\n",
                                WSTOPSIG (status), name (WSTOPSIG (status)));
                  else
                    printstats ("OK\n");

                  if (mark == TLE)
                    {
                      /* Adjust the timings... although we know the child   *
                       * was been killed just in the right time seing 1.990 *
                       * as TLE when the limit is 2 seconds is anoying      */
                      usage.ru_utime.tv_sec = profile.cpu;
                      usage.ru_utime.tv_usec = 0;
                      printstats ("Time Limit Exceeded\n");
                    }
                  else if (mark == OLE)
                    printstats ("Output Limit Exceeded\n");
                  else if (mark == RTLE)
                    printstats ("Time Limit Exceeded\n");
                  else if (mark == RF)
                    printstats ("Invalid Function\n");
                  else if (mark == IE)
                    printstats ("Internal Error\n");
                }
            }
          printstats ("elapsed time: %d seconds\n", ttarget - tsource);
          printstats ("memory usage: %d kbytes\n", mem);
          printstats ("cpu usage: %0.3f seconds\n",
                      (float) miliseconds (&usage.ru_utime) / 1000.0);
        }
    }
  fclose (redirect);

  return (EXIT_SUCCESS);
}