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 mount points 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;
}