Sandboxing

In the context of security integration, a sandbox is a mechanism for constraining code with virtual walls to protect it from being damaged by malicious code. You can also use a sandbox to limit the damage done if the code it contains is co-opted by an attacker.

Best practices for security integrators include protecting mountpoints from client access by sandboxing them. Application sandboxing (including third-party applications) can reduce vulnerability to malware. Sandboxes are also a convenient, isolated space for testing your code. Use the procmgr ability _PROCMGR_AID_SANDBOX to create and delete sandboxes, attach a process to a sandbox, and detach a process from a sandbox.

To learn more about procmgr abilities, see the Procmgr abilities chapter of the QNX Neutrino Programmer's Guide.

Note: Child processes inherit the sandbox of their parent.

Example: Attaching a sandbox to a process

The following example shows how to use procmgr abilities to create a sandbox, attach a process to the sandbox, and then delete the sandbox:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sandbox.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sys/neutrino.h>
#include <sys/iomsg.h>
#include <sys/procmsg.h>

static const char sandbox_config[] =
        "[version=1]\n"
        "/proc/boot\n"
        "/dev/tty*\n"
        "/tmp\n"
        "/root\n"
        "/usr/lib\n"
        "!*";

int main(int argc, char *argv[])
{
   proc_sandbox_create_t   msg;
   iov_t                   iov[2];
   int                     r;
   int			   sbid;

   fprintf(stderr, "Initializing sandbox configuration\n");
   r = sandbox_parse_config(sandbox_config, sizeof(sandbox_config), &iov[1], &msg.i.version);
   if (r > 0) {
      fprintf(stderr, "Parse error on line %d\n", r);
      return 1;
   } else if (r < 0) {
      errno = r;
      perror("sandbox_parse_config");
      return 1;
   } else {
      fprintf(stderr, "%s:%d - Creating sandbox...\n", __FUNCTION__, __LINE__); 
      msg.i.type = _PROC_SANDBOX;
      msg.i.subtype = _PROC_SANDBOX_CREATE;
      msg.i.datalen = iov[1].iov_len;
      iov[0].iov_base = &msg;
      iov[0].iov_len = sizeof(msg);

      if (MsgSendv(PROCMGR_COID, iov, 2, iov, 1) != 0) {
         perror("MsgSendv(_PROC_SANDBOX_CREATE)");
         return 1;
      }
      sbid = msg.o.sbid;
      sandbox_done_config(&iov[1]);
   }


   // Start the child process.
   pid_t   pid = fork();
   if (pid < 0) {
      perror("fork");
      return 1;
   }

   if (pid == 0) {
      delay(1000); // wait for parent to attach child to sandbox
      if (execl("/proc/boot/sh", "proc/boot/sh", NULL) < 0) {     /* execute the command  */
         printf("*** ERROR: exec failed errno:%d\n", errno);
         exit(1);
      }
      fprintf(stderr, "%s:%d - execl exitting\n", __FUNCTION__, __LINE__); 
   }

   fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__); 
   r = sandbox_attach(sbid, pid);
   if (r < 0) {
      fprintf(stderr, "sandbox_attach: %s\n", strerror(-r));
      goto done;
   }
   fprintf(stderr, "%s:%d pid=%d r=%d\n", __FUNCTION__, __LINE__, pid, r); 

   waitpid(pid, &r, 0);
   fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__); 
   pid = 0;

done:
   if (sbid != -1) {
      sandbox_delete(sbid);
   }
   return r;
}