Ejemplo n.º 1
0
Archivo: sandbox.c Proyecto: hsn10/tor
/**
 * Function responsible for setting up the epoll_ctl syscall for
 * the seccomp filter sandbox.
 *
 *  Note: basically allows everything but will keep for now..
 */
static int
sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  (void) filter;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 1,
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_ADD));
  if (rc)
    return rc;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 1,
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_MOD));
  if (rc)
    return rc;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 1,
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_DEL));
  if (rc)
    return rc;

  return 0;
}
Ejemplo n.º 2
0
/**
 * Function responsible for setting up the socket syscall for
 * the seccomp filter sandbox.
 */
static int
sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  int i;
  (void) filter;

#ifdef __i386__
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket));
  if (rc)
    return rc;
#endif

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
      SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM));
  if (rc)
    return rc;

  for (i = 0; i < 2; ++i) {
    const int pf = i ? PF_INET : PF_INET6;

    rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
      SCMP_CMP(0, SCMP_CMP_EQ, pf),
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM),
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_TCP));
    if (rc)
      return rc;

    rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
      SCMP_CMP(0, SCMP_CMP_EQ, pf),
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_DGRAM),
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
    if (rc)
      return rc;
  }

  rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
      SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_RAW),
      SCMP_CMP(2, SCMP_CMP_EQ, 0));
  if (rc)
    return rc;

  return 0;
}
Ejemplo n.º 3
0
/**
 * Function responsible for setting up the getsockopt syscall for
 * the seccomp filter sandbox.
 */
static int
sb_getsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  (void) filter;

#ifdef __i386__
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt));
  if (rc)
    return rc;
#endif

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_ERROR));
  if (rc)
    return rc;

#ifdef HAVE_SYSTEMD
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF));
  if (rc)
    return rc;
#endif

#ifdef HAVE_LINUX_NETFILTER_IPV4_H
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_ORIGINAL_DST));
  if (rc)
    return rc;
#endif

#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IPV6),
      SCMP_CMP(2, SCMP_CMP_EQ, IP6T_SO_ORIGINAL_DST));
  if (rc)
    return rc;
#endif

  return 0;
}
Ejemplo n.º 4
0
int main(int const argc, char * const * const argv)
{
	try
	{
		alarm(10);

		close(fileno(stdin));
		for (int fd = fileno(stderr); fd != 1024; ++fd) close(fd);
		dup2(fileno(stdout), fileno(stderr));

		limitResource(RLIMIT_CPU, 9, 11);
		limitResource(RLIMIT_AS, 512*1024*1024);
		limitResource(RLIMIT_DATA, 512*1024*1024);
		limitResource(RLIMIT_FSIZE, 10*1024*1024);
		limitResource(RLIMIT_LOCKS, 0);
		limitResource(RLIMIT_MEMLOCK, 0);
		limitResource(RLIMIT_NPROC, 16);

		if (argc < 2) e("params: program args");

		if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) e("prctl");

		scmp_filter_ctx const ctx = seccomp_init(SCMP_ACT_TRAP);

		if (!ctx) e("seccomp_init");

		if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 1,
			SCMP_CMP(0, SCMP_CMP_MASKED_EQ, CLONE_THREAD, CLONE_THREAD)) != 0)
			e("seccomp_rule_add");

		for (auto && p : rules)
			if (seccomp_rule_add(ctx, p.second, p.first, 0) != 0)
				e("seccomp_rule_add");

		if (seccomp_load(ctx) < 0) e("seccomp_load");

		execv(argv[1], argv + 1);
		e("execv");
	}
	catch (std::exception const & e)
	{
		std::cerr << "exception: " << e.what() << '\n';
		return 1;
	}
}
Ejemplo n.º 5
0
/**
 * Function responsible for setting up the setsockopt syscall for
 * the seccomp filter sandbox.
 */
static int
sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  (void) filter;

#ifdef __i386__
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt));
  if (rc)
    return rc;
#endif

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_REUSEADDR));
  if (rc)
    return rc;

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF));
  if (rc)
    return rc;

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_RCVBUF));
  if (rc)
    return rc;

#ifdef IP_TRANSPARENT
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
      SCMP_CMP(2, SCMP_CMP_EQ, IP_TRANSPARENT));
  if (rc)
    return rc;
#endif

  return 0;
}
Ejemplo n.º 6
0
/**
 * Function responsible for setting up the rt_sigaction syscall for
 * the seccomp filter sandbox.
 */
static int
sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  unsigned i;
  int rc;
  int param[] = { SIGINT, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGCHLD,
#ifdef SIGXFSZ
      SIGXFSZ
#endif
      };
  (void) filter;

  for (i = 0; i < ARRAY_LENGTH(param); i++) {
    rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction),
        SCMP_CMP(0, SCMP_CMP_EQ, param[i]));
    if (rc)
      break;
  }

  return rc;
}
Ejemplo n.º 7
0
/**
 * Function responsible for setting up the accept4 syscall for
 * the seccomp filter sandbox.
 */
static int
sb_accept4(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  (void)filter;

#ifdef __i386__
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall),
      SCMP_CMP(0, SCMP_CMP_EQ, 18));
  if (rc) {
    return rc;
  }
#endif

  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4),
                   SCMP_CMP_MASKED(3, SOCK_CLOEXEC|SOCK_NONBLOCK, 0));
  if (rc) {
    return rc;
  }

  return 0;
}
Ejemplo n.º 8
0
/**
 * Function responsible for setting up the stat64 syscall for
 * the seccomp filter sandbox.
 */
static int
sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  sandbox_cfg_t *elem = NULL;

  // for each dynamic parameter filters
  for (elem = filter; elem != NULL; elem = elem->next) {
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 && (param->syscall == SCMP_SYS(open)
        || param->syscall == SCMP_SYS(stat64))) {
      rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat64), 1,
          SCMP_CMP(0, SCMP_CMP_EQ, param->value));
      if (rc != 0) {
        log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
            "libseccomp  error %d", rc);
        return rc;
      }
    }
  }

  return 0;
}
Ejemplo n.º 9
0
/**
 * Protects all the strings in the sandbox's parameter list configuration. It
 * works by calculating the total amount of memory required by the parameter
 * list, allocating the memory using mmap, and protecting it from writes with
 * mprotect().
 */
static int
prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
{
  int ret = 0;
  size_t pr_mem_size = 0, pr_mem_left = 0;
  char *pr_mem_next = NULL, *pr_mem_base;
  sandbox_cfg_t *el = NULL;
  strmap_t *locations = NULL;

  // get total number of bytes required to mmap. (Overestimate.)
  for (el = cfg; el != NULL; el = el->next) {
    pr_mem_size += strlen((char*) el->param->value) + 1;
    if (el->param->value2)
      pr_mem_size += strlen((char*) el->param->value2) + 1;
  }

  // allocate protected memory with MALLOC_MP_LIM canary
  pr_mem_base = (char*) mmap(NULL, MALLOC_MP_LIM + pr_mem_size,
      PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
  if (pr_mem_base == MAP_FAILED) {
    log_err(LD_BUG,"(Sandbox) failed allocate protected memory! mmap: %s",
        strerror(errno));
    ret = -1;
    goto out;
  }

  pr_mem_next = pr_mem_base + MALLOC_MP_LIM;
  pr_mem_left = pr_mem_size;

  locations = strmap_new();

  // change el value pointer to protected
  for (el = cfg; el != NULL; el = el->next) {
    if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left,
                            &el->param->value) < 0) {
      ret = -2;
      goto out;
    }
    if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left,
                            &el->param->value2) < 0) {
      ret = -2;
      goto out;
    }
    el->param->prot = 1;
  }

  // protecting from writes
  if (mprotect(pr_mem_base, MALLOC_MP_LIM + pr_mem_size, PROT_READ)) {
    log_err(LD_BUG,"(Sandbox) failed to protect memory! mprotect: %s",
        strerror(errno));
    ret = -3;
    goto out;
  }

  /*
   * Setting sandbox restrictions so the string memory cannot be tampered with
   */
  // no mremap of the protected base address
  ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(mremap),
      SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) mremap protected memory filter fail!");
    goto out;
  }

  // no munmap of the protected base address
  ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(munmap),
        SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) munmap protected memory filter fail!");
    goto out;
  }

  /*
   * Allow mprotect with PROT_READ|PROT_WRITE because openssl uses it, but
   * never over the memory region used by the protected strings.
   *
   * PROT_READ|PROT_WRITE was originally fully allowed in sb_mprotect(), but
   * had to be removed due to limitation of libseccomp regarding intervals.
   *
   * There is a restriction on how much you can mprotect with R|W up to the
   * size of the canary.
   */
  ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
      SCMP_CMP(0, SCMP_CMP_LT, (intptr_t) pr_mem_base),
      SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (LT)!");
    goto out;
  }

  ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
      SCMP_CMP(0, SCMP_CMP_GT, (intptr_t) pr_mem_base + pr_mem_size +
          MALLOC_MP_LIM),
      SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (GT)!");
    goto out;
  }

 out:
  strmap_free(locations, NULL);
  return ret;
}
Ejemplo n.º 10
0
/**
 * Protects all the strings in the sandbox's parameter list configuration. It
 * works by calculating the total amount of memory required by the parameter
 * list, allocating the memory using mmap, and protecting it from writes with
 * mprotect().
 */
static int
prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
{
  int ret = 0;
  size_t pr_mem_size = 0, pr_mem_left = 0;
  char *pr_mem_next = NULL, *pr_mem_base;
  sandbox_cfg_t *el = NULL;

  // get total number of bytes required to mmap
  for (el = cfg; el != NULL; el = el->next) {
    pr_mem_size += strlen((char*) ((smp_param_t*)el->param)->value) + 1;
  }

  // allocate protected memory with MALLOC_MP_LIM canary
  pr_mem_base = (char*) mmap(NULL, MALLOC_MP_LIM + pr_mem_size,
      PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
  if (pr_mem_base == MAP_FAILED) {
    log_err(LD_BUG,"(Sandbox) failed allocate protected memory! mmap: %s",
        strerror(errno));
    ret = -1;
    goto out;
  }

  pr_mem_next = pr_mem_base + MALLOC_MP_LIM;
  pr_mem_left = pr_mem_size;

  // change el value pointer to protected
  for (el = cfg; el != NULL; el = el->next) {
    char *param_val = (char*)((smp_param_t *)el->param)->value;
    size_t param_size = strlen(param_val) + 1;

    if (pr_mem_left >= param_size) {
      // copy to protected
      memcpy(pr_mem_next, param_val, param_size);

      // re-point el parameter to protected
      {
        void *old_val = (void *) ((smp_param_t*)el->param)->value;
        tor_free(old_val);
      }
      ((smp_param_t*)el->param)->value = (intptr_t) pr_mem_next;
      ((smp_param_t*)el->param)->prot = 1;

      // move next available protected memory
      pr_mem_next += param_size;
      pr_mem_left -= param_size;
    } else {
      log_err(LD_BUG,"(Sandbox) insufficient protected memory!");
      ret = -2;
      goto out;
    }
  }

  // protecting from writes
  if (mprotect(pr_mem_base, MALLOC_MP_LIM + pr_mem_size, PROT_READ)) {
    log_err(LD_BUG,"(Sandbox) failed to protect memory! mprotect: %s",
        strerror(errno));
    ret = -3;
    goto out;
  }

  /*
   * Setting sandbox restrictions so the string memory cannot be tampered with
   */
  // no mremap of the protected base address
  ret = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(mremap), 1,
      SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) mremap protected memory filter fail!");
    return ret;
  }

  // no munmap of the protected base address
  ret = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(munmap), 1,
        SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) munmap protected memory filter fail!");
    return ret;
  }

  /*
   * Allow mprotect with PROT_READ|PROT_WRITE because openssl uses it, but
   * never over the memory region used by the protected strings.
   *
   * PROT_READ|PROT_WRITE was originally fully allowed in sb_mprotect(), but
   * had to be removed due to limitation of libseccomp regarding intervals.
   *
   * There is a restriction on how much you can mprotect with R|W up to the
   * size of the canary.
   */
  ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 2,
      SCMP_CMP(0, SCMP_CMP_LT, (intptr_t) pr_mem_base),
      SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (LT)!");
    return ret;
  }

  ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 2,
      SCMP_CMP(0, SCMP_CMP_GT, (intptr_t) pr_mem_base + pr_mem_size +
          MALLOC_MP_LIM),
      SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
  if (ret) {
    log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (GT)!");
    return ret;
  }

 out:
   return ret;
}
Ejemplo n.º 11
0
/**
 * Function responsible for setting up the socket syscall for
 * the seccomp filter sandbox.
 */
static int
sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  (void) filter;

#ifdef __i386__
  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0);
  if (rc)
    return rc;
#endif

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 3,
      SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK),
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
  if (rc)
    return rc;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 3,
      SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC),
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_TCP));
  if (rc)
    return rc;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 3,
      SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK),
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_TCP));
  if (rc)
    return rc;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 3,
      SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK),
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
  if (rc)
    return rc;

  rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 3,
      SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_RAW),
      SCMP_CMP(2, SCMP_CMP_EQ, 0));
  if (rc)
    return rc;

  return 0;
}
Ejemplo n.º 12
0
static int parse_line(char *line, struct seccomp_args *sargs)
{
	// strtok_r needs a pointer to keep track of where it is in the
	// string.
	char *buf_saveptr;

	// Initialize our struct
	sargs->length = 0;
	sargs->syscall_nr = -1;

	if (strlen(line) == 0)
		return PARSE_ERROR;

	// Initialize tokenizer and obtain first token.
	char *buf_token = strtok_r(line, " \t", &buf_saveptr);
	if (buf_token == NULL)
		return PARSE_ERROR;

	// syscall not available on this arch/kernel
	sargs->syscall_nr = seccomp_syscall_resolve_name(buf_token);
	if (sargs->syscall_nr == __NR_SCMP_ERROR)
		return PARSE_INVALID_SYSCALL;

	// Parse for syscall arguments. Since we haven't yet searched for the
	// next token, buf_token is still the syscall itself so start 'pos' as
	// -1 and only if there is an arg to parse, increment it.
	int pos = -1;
	while (pos < SC_ARGS_MAXLENGTH) {
		buf_token = strtok_r(NULL, " \t", &buf_saveptr);
		if (buf_token == NULL)
			break;
		// we found a token, so increment position and process it
		pos++;
		if (strcmp(buf_token, "-") == 0)	// skip arg
			continue;

		enum scmp_compare op = -1;
		scmp_datum_t value = 0;
		if (strlen(buf_token) == 0) {
			return PARSE_ERROR;
		} else if (strlen(buf_token) == 1) {
			// syscall N (length of '1' indicates a single digit)
			op = SCMP_CMP_EQ;
			value = read_number(buf_token);
		} else if (strncmp(buf_token, ">=", 2) == 0) {
			// syscall >=N
			op = SCMP_CMP_GE;
			value = read_number(&buf_token[2]);
		} else if (strncmp(buf_token, "<=", 2) == 0) {
			// syscall <=N
			op = SCMP_CMP_LE;
			value = read_number(&buf_token[2]);
		} else if (strncmp(buf_token, "!", 1) == 0) {
			// syscall !N
			op = SCMP_CMP_NE;
			value = read_number(&buf_token[1]);
		} else if (strncmp(buf_token, ">", 1) == 0) {
			// syscall >N
			op = SCMP_CMP_GT;
			value = read_number(&buf_token[1]);
		} else if (strncmp(buf_token, "<", 1) == 0) {
			// syscall <N
			op = SCMP_CMP_LT;
			value = read_number(&buf_token[1]);
		} else {
			// syscall NNN
			op = SCMP_CMP_EQ;
			value = read_number(buf_token);
		}
		if (errno != 0)
			return PARSE_ERROR;

		sargs->arg_cmp[sargs->length] = SCMP_CMP(pos, op, value);
		sargs->length++;

		//printf("\nDEBUG: SCMP_CMP(%d, %d, %llu)\n", pos, op, value);
	}
	// too many args
	if (pos >= SC_ARGS_MAXLENGTH)
		return PARSE_ERROR;

	return PARSE_OK;
}
Ejemplo n.º 13
0
/**
 * Initialize seccomp.
 *
 * @param remote file descriptor to talk with the unprivileged process
 * @param monitored monitored child
 * @return negative on failures or 0 if everything was setup
 */
int
priv_seccomp_init(int remote, int child)
{
	int rc = -1;
	scmp_filter_ctx ctx;

	log_debug("seccomp", "initialize libseccomp filter");
	monitored = child;
	if (priv_seccomp_trap_install() < 0) {
		log_warn("seccomp", "unable to install SIGSYS handler");
		goto failure_scmp;
	}

	if ((ctx = seccomp_init(SCMP_ACT_TRAP)) == NULL) {
		log_warnx("seccomp", "unable to initialize libseccomp subsystem");
		goto failure_scmp;
	}

	if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
		    SCMP_SYS(read), 1, SCMP_CMP(0, SCMP_CMP_EQ, remote))) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
		SCMP_SYS(write), 1, SCMP_CMP(0, SCMP_CMP_EQ, remote))) < 0) {
		errno = -rc;
		log_warn("seccomp", "unable to allow read/write on remote socket");
		goto failure_scmp;
	}

	/* We are far more generic from here. */
	if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0)) < 0 || /* write needed for */
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(bind), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(uname), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(wait4), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0)) < 0 ||
	    /* The following are for resolving addresses */
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0)) < 0 ||
	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0)) < 0 ||

	    (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0)) < 0) {
		errno = -rc;
		log_warn("seccomp", "unable to build seccomp rules");
		goto failure_scmp;
	}

	if ((rc = seccomp_load(ctx)) < 0) {
		errno = -rc;
		log_warn("seccomp", "unable to load libseccomp filter");
		goto failure_scmp;
	}

failure_scmp:
	seccomp_release(ctx);
	return rc;
}
Ejemplo n.º 14
0
void GenHash::calcGenHash()
{
    sandbox_init();

    // cannot excute execve
    prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
    kDebug() << "execve" << execve("ls",NULL,NULL);

    if (child_pid){

        KParts::ReadOnlyPart * part = qobject_cast<KParts::ReadOnlyPart *>(parent());

        QFile file(KFileDialog::getOpenFileName(KUrl("kfiledialog:///konqueror"), i18n("*"), part->widget(), i18n("Open File To make MD5.")));

        if (!file.open(QIODevice::ReadOnly))
        {
            return;
        }

        // TODO QFile
        //char s[1024];

        // write file content
        {
            close(pipe_fd[0]);
            QByteArray s = file.readAll();
            char *ch = s.data();
            if (write(pipe_fd[1], ch, s.size()) < 0) {
                perror("write");
            }
            close(pipe_fd[1]);
        }

        //read result
        {
            close(pipe_result_fd[1]);
            char result[128];
            if (read(pipe_result_fd[0], &result[0], 128) < 0){
                perror("read");
            }
            close(pipe_result_fd[0]);

            KMessageBox::information(part->widget(),i18n("Md5 : %1").arg(QString(QByteArray(result, 128))));
        }

    }else{

        scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
        seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
        seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 3,
                                   SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)pipe_fd[0]),
                                   SCMP_A1(SCMP_CMP_EQ, (scmp_datum_t)buff),
                                   SCMP_A2(SCMP_CMP_LE, 1024));
        seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
                                    SCMP_CMP(0, SCMP_CMP_EQ, (scmp_datum_t)pipe_result_fd[1]));

        seccomp_load(ctx);
        seccomp_release(ctx);

        calcMD5();
    }
}
Ejemplo n.º 15
0
int main(int argc, char* argv[], char* envp[]) {
    
    if (argc<3 || !strcmp(argv[1], "-?") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "--version")) {
        fprintf(stderr, "Usage: limit_syscalls syscall1 syscall2 ... syscallN -- program [arguments]\n");
        fprintf(stderr, "Example:\n"
            "   limit_syscalls execve exit write read open close mmap2  fstat64 access  mprotect set_thread_area -- /bin/echo qqq\n");
        fprintf(stderr, "Advanced:\n");
        fprintf(stderr, "   LIMIT_SYSCALLS_DEFAULT_ACTION={a,k,eN} - by default allow, kill or return error N\n");
        fprintf(stderr, "   some_syscall,A0>=3,A4<<1000,A1!=4,A2&&0x0F==0x0F - compare arguments\n");
        fprintf(stderr, "   some_syscall,{a,k,eN} - allow, kill or return error N for this rule\n");
        fprintf(stderr, "Some more example:\n");
        fprintf(stderr,"    LIMIT_SYSCALLS_DEFAULT_ACTION=a  limit_syscalls  'write,A0==1,e0' -- /usr/bin/printf --help\n");
        fprintf(stderr,"     (this makes write to stdout in /usr/bin/printf silently fail, looping it)\n");
        return 126;
    }
    
    // ECHRNG, just to provide more or less noticable message when we block a syscall
    uint32_t default_action = SCMP_ACT_ERRNO(44);
    
    if (getenv("LIMIT_SYSCALLS_DEFAULT_ACTION")) {
        const char* e = getenv("LIMIT_SYSCALLS_DEFAULT_ACTION");
        if(!strcmp(e, "a")) default_action=SCMP_ACT_ALLOW;
        else 
        if(!strcmp(e, "k")) default_action=SCMP_ACT_KILL;
        else
        if(e[0] == 'e') {
            int errno_;
            if (sscanf(e+1,"%i", &errno_)!=1) {
                fprintf(stderr, "LIMIT_SYSCALLS_DEFAULT_ACTION=e<number> expected\n");
                return 109;
            }
            default_action=SCMP_ACT_ERRNO(errno_);
        }
        else
        {
            fprintf(stderr, "LIMIT_SYSCALLS_DEFAULT_ACTION should be a, k or e<number>\n");
            return 110;
        } 
    }
    
    scmp_filter_ctx ctx = seccomp_init(default_action);
    if (!ctx) {
        perror("seccomp_init");
        return 126;
    }
    
    int i;
    
    for (i=1; i<argc; ++i) {
        if (!strcmp(argv[i], "--")) break;
            
        const char* syscall_name = strtok(argv[i], ",");
                
        int syscall = seccomp_syscall_resolve_name(argv[i]);
        
        if (syscall == __NR_SCMP_ERROR) {
            fprintf(stderr, "Failed to resolve syscall %s\n", syscall_name);
            return 125;
        }
        
        int nargs = 0;
        struct scmp_arg_cmp args[6];
        
        uint32_t action = SCMP_ACT_ALLOW;
        
        const char* aa = strtok(NULL, ",");
        for (;aa; aa=strtok(NULL, ",")) {
            if (aa[0]=='A') {
                if(nargs==6) {
                    fprintf(stderr, "Maximum comparator count (6) exceed in %s\n", argv[i]);
                    return 103;
                }
                if( !(aa[1]>='0' && aa[1]<='5') ) {
                    fprintf(stderr, "A[0-5] expected in %s\n", argv[i]);
                    return 100;
                }
                int cmp = 0; /* invalid value */
                
                if(!strncmp(aa+2, "!=", 2)) cmp=SCMP_CMP_NE;
                if(!strncmp(aa+2, "<<", 2)) cmp=SCMP_CMP_LT;
                if(!strncmp(aa+2, "<=", 2)) cmp=SCMP_CMP_LE;
                if(!strncmp(aa+2, "==", 2)) cmp=SCMP_CMP_EQ;
                if(!strncmp(aa+2, ">=", 2)) cmp=SCMP_CMP_GE;
                if(!strncmp(aa+2, ">>", 2)) cmp=SCMP_CMP_GT;
                if(!strncmp(aa+2, "&&", 2)) cmp=SCMP_CMP_MASKED_EQ;
                    
                if (!cmp) {
                    fprintf(stderr, "After An there should be comparison operator like"
                        " != << <= == => >> ot &&; in %s\n", argv[i]);
                    return 101;
                }
                
                if (cmp != SCMP_CMP_MASKED_EQ) {
                    scmp_datum_t datum;
                    if(sscanf(aa+4, "%lli", &datum)!=1) {
                        fprintf(stderr, "After AxOP there should be some sort of number in %s\n", argv[i]);
                        return 102;
                    }
                    
                    args[nargs++] = SCMP_CMP(aa[1]-'0', cmp, datum);
                } else {
                    scmp_datum_t mask;
                    scmp_datum_t datum;
                    if(sscanf(aa+4, "%lli==%lli", &mask, &datum)!=2) {
                        fprintf(stderr, "After Ax&& there should be number==number; in %s\n", argv[i]);
                        return 104;
                    }
                    
                    args[nargs++] = SCMP_CMP(aa[1]-'0', SCMP_CMP_MASKED_EQ, mask, datum);
                }
            } else
            if (aa[0]=='e') {
                int errno_;
                if (sscanf(aa+1,"%i", &errno_)!=1) {
                    fprintf(stderr, "After e should be number in %s\n", argv[i]);
                    return 105;
                }
                
                action = SCMP_ACT_ERRNO(errno_);
            } else
            if (aa[0]=='k') {
                action = SCMP_ACT_KILL;
            } else
            if (aa[0]=='a') {
                action = SCMP_ACT_ALLOW;
            } else {
                fprintf(stderr, "Unknown %c in %s\n", aa[0], argv[i]);
                return 107;
            }
        }
        
        int ret = seccomp_rule_add_hack(ctx, action, syscall, nargs, args);
        
        if (ret!=0) {
            fprintf(stderr, "seccomp_rule_add returned %d\n", ret);
            return 124;
        }
    }
    
    int ret = seccomp_load(ctx);
    if (ret!=0) {
        fprintf(stderr, "seccomp_load returned %d\n", ret);        
    }
    
    execve(argv[i+1], argv+i+1, envp);
    
    perror("execve");    
    return 123;
}
Ejemplo n.º 16
0
/**
 * Function responsible for setting up the mmap2 syscall for
 * the seccomp filter sandbox.
 */
static int
sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  (void)filter;

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE));
  if (rc) {
    return rc;
  }

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE));
  if (rc) {
    return rc;
  }

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS));
  if (rc) {
    return rc;
  }

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
       SCMP_CMP(3, SCMP_CMP_EQ,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK));
  if (rc) {
    return rc;
  }

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE));
  if (rc) {
    return rc;
  }

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS));
  if (rc) {
    return rc;
  }

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_EXEC),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_DENYWRITE));
  if (rc) {
    return rc;
  }

  return 0;
}
int main(int argc, char *argv[])
{
  const char *argv0 = argv[0];
  int opt, optidx;

  bool separate_read_write = false;

  bool proxy = false;
  struct sockaddr_in proxy_sin;

  bool join = false;

#ifdef HAVE_SECCOMP
  int nrules = 0;
  uint32_t def_action = SCMP_ACT_ALLOW;
  char *fixed = (char *)mmap((void *)0x800000, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
#endif

  struct option longopts[] = {
    {"abstract"    , no_argument       , 0 , 'a'} ,
    {"directory"   , required_argument , 0 , 'd'} ,
    {"environment" , required_argument , 0 , 'e'} ,
    {"join"        , no_argument       , 0 , 'j'} ,
    {"policy"      , required_argument , 0 , 'o'} ,
    {"proxy"       , required_argument , 0 , 'p'} ,
    {"seccomp"     , required_argument , 0 , 'c'} ,
    {"separate"    , no_argument       , 0 , 's'} ,
    {0             , 0                 , 0 , 0}   ,
  };
  while ((opt = getopt_long(argc, argv, "+0ac:d:e:hjo:p:s", longopts, &optidx)) != -1) {
    switch (opt) {
    case 'a':
      af_unix = true;
      break;
    case 'c': {
#ifdef HAVE_SECCOMP
      char *pp = optarg, *p, *qq, *q, *saved0, *saved1;
      for (; ; pp = NULL) {
        p = strtok_r(pp, " \t,", &saved0);
        if (! p) break;

        bool negative = false;
        int num, pos, nfilters = 0;
        enum scmp_compare op;
        if (nrules >= SIZE(scmp_rules))
          errx(BAD_ARG, "too many rules");
        if (*p == '+')
          p++;
        else if (*p == '-')
          p++, negative = true;
        scmp_rules[nrules].action = negative ? SCMP_ACT_TRAP : SCMP_ACT_ALLOW;

        for (qq = p; ; qq = NULL) {
          q = strtok_r(qq, ":", &saved1);
          if (! q) break;
          if (qq) {
            num = seccomp_syscall_resolve_name(q);
            if (num < 0)
              errx(BAD_ARG, "unknown syscall \"%s\"", q);
            scmp_rules[nrules].syscall = num;
          } else {
            if (nfilters >= SIZE(scmp_rules[0].arg_array))
              errx(BAD_ARG, "too many filters");
            if (! ('0' <= *q && *q <= '5'))
              errx(BAD_ARG, "argument position should be 0-5");
            pos = *q-'0';
            REP(i, nfilters)
              if (pos == scmp_rules[nrules].arg_array[i].arg)
                errx(BAD_ARG, "duplicate argument position %d", pos);
            q++;
            if (*q == '=')
              q++, op = SCMP_CMP_EQ;
            else if (*q == '!' && q[1] == '=')
              q += 2, op = SCMP_CMP_NE;
            else if (*q == '<') {
              if (q[1] == '=')
                q += 2, op = SCMP_CMP_LE;
              else
                q++, op = SCMP_CMP_LT;
            } else if (*q == '>') {
              if (q[1] == '=')
                q += 2, op = SCMP_CMP_GE;
              else
                q++, op = SCMP_CMP_GT;
            }
            else
              errx(BAD_ARG, "unknown operator \"%c\"", *q);
            scmp_datum_t val = strtol(q, &q, 0);
            if (*q)
              errx(BAD_ARG, "invalid number");
            scmp_rules[nrules].arg_array[nfilters++] = SCMP_CMP(pos, op, val);
          }
        }
        scmp_rules[nrules].arg_cnt = nfilters;
        nrules++;
      }
#else
      errx(ERR_SYSCALL, "HAVE_SECCOMP not enabled");
#endif
      break;
    }
    case 'd':
      Chdir(optarg);
      break;
    case 'h':
      show_help(STDOUT_FILENO, argv0);
      break;
    case 'j':
      join = true;
      break;
    case 'e':
      putenv(optarg);
      break;
    case 'o':
#ifdef HAVE_SECCOMP
      if (optarg[0] == 'k')
        def_action = SCMP_ACT_KILL;
      else if (optarg[0] == 't')
        def_action = SCMP_ACT_TRAP;
      else if (optarg[0] == 'a')
        def_action = SCMP_ACT_ALLOW;
#else
      errx(ERR_SYSCALL, "HAVE_SECCOMP not enabled");
#endif
      break;
    case 'p': // proxy
      {
        char *p = strchr(optarg, ':');
        if (! p)
          errx(BAD_ARG, "no semicolon");
        *p = '\0';
        proxy_sin.sin_family = AF_INET;
        if (inet_aton(optarg, &proxy_sin.sin_addr) < 0)
          errx(BAD_ARG, "gethostbyname: %s", strerror(errno));
        proxy_sin.sin_port = htons(strtol(p+1, &p, 10));
        if (*p)
          errx(BAD_ARG, "port");
        proxy = true;
      }
      break;
    case 's':
      separate_read_write = true;
      break;
    default:
      show_help(STDERR_FILENO, argv0);
      break;
    }
  }

  argc -= optind;
  argv += optind;

  if (argc < 1) {
    show_help(STDERR_FILENO, argv0);
    return BAD_ARG;
  }

  char buf[4096];
  int pipe_p2c[2], pipe_c2p1[2], pipe_c2p2[2];
  if (af_unix) {
    unix_p2c.sun_family = AF_UNIX; 
    unix_c2p1.sun_family = AF_UNIX;
    unix_c2p2.sun_family = AF_UNIX;
    unix_p2c.sun_path[0] = '\0';
    unix_c2p1.sun_path[0] = '\0';
    unix_c2p2.sun_path[0] = '\0';
    sprintf(unix_p2c.sun_path+1, "/tmp/unix/%d-%d.in", getuid(), getpid());
    sprintf(unix_c2p1.sun_path+1, "/tmp/unix/%d-%d.out", getuid(), getpid());
    sprintf(unix_c2p2.sun_path+1, "/tmp/unix/%d-%d.err", getuid(), getpid());
    pipe_p2c[0] = socket(AF_UNIX, SOCK_STREAM, 0);
    pipe_c2p1[1] = socket(AF_UNIX, SOCK_STREAM, 0);
    if (! join)
      pipe_c2p2[1] = socket(AF_UNIX, SOCK_STREAM, 0);
    atexit(atexit_rm);
    if (bind(pipe_p2c[0], &unix_p2c, sizeof unix_p2c) < 0 ||
        bind(pipe_c2p1[1], &unix_c2p1, sizeof unix_c2p1) < 0)
      return perror(""), 0;
    if (! join && bind(pipe_c2p2[1], &unix_c2p2, sizeof unix_c2p2) < 0)
      return perror(""), 0;
    if (listen(pipe_p2c[0], 1) < 0 ||
        listen(pipe_c2p1[1], 1) < 0)
      return perror(""), 0;
    if (! join && listen(pipe_c2p2[1], 1) < 0)
      return perror(""), 0;
  } else {
    Pipe(pipe_p2c);
    Pipe(pipe_c2p1);
    if (! join)
      Pipe(pipe_c2p2);
  }

  child = Fork();
  if (! child) {
    // child
    if (af_unix) {
      // close bound sockets
      close(pipe_p2c[0]);
      close(pipe_c2p1[1]);
      close(pipe_c2p2[1]);

      // domain sockets for client
      pipe_p2c[1] = socket(AF_UNIX, SOCK_STREAM, 0);
      pipe_c2p1[0] = socket(AF_UNIX, SOCK_STREAM, 0);
      if (! join)
        pipe_c2p2[0] = socket(AF_UNIX, SOCK_STREAM, 0);

      if (connect(pipe_p2c[1], &unix_p2c, sizeof unix_p2c) < 0 ||
          connect(pipe_c2p1[0], &unix_c2p1, sizeof unix_c2p1) < 0)
        return 0;
      dup2(pipe_p2c[1], STDIN_FILENO); close(pipe_p2c[1]);
      dup2(pipe_c2p1[0], STDOUT_FILENO); close(pipe_c2p1[0]);
      if (join)
        dup2(STDOUT_FILENO, STDERR_FILENO);
      else {
        connect(pipe_c2p2[0], &unix_c2p2, sizeof unix_c2p2);
        dup2(pipe_c2p2[0], STDERR_FILENO); close(pipe_c2p2[0]);
      }
    } else {
      close(pipe_p2c[1]); dup2(pipe_p2c[0], STDIN_FILENO); close(pipe_p2c[0]);
      close(pipe_c2p1[0]); dup2(pipe_c2p1[1], STDOUT_FILENO); close(pipe_c2p1[1]);
      if (join)
        dup2(STDOUT_FILENO, STDERR_FILENO);
      else {
        close(pipe_c2p2[0]); dup2(pipe_c2p2[1], STDERR_FILENO); close(pipe_c2p2[1]);
      }
    }

#ifdef HAVE_SECCOMP
    scmp_filter_ctx ctx = seccomp_init(def_action);
    if (ctx == NULL)
      return 1;
    REP(i, nrules) {
      int ret = seccomp_rule_add_array(ctx, scmp_rules[i].action, scmp_rules[i].syscall,
                                       scmp_rules[i].arg_cnt, scmp_rules[i].arg_array);
      if (ret < 0)
        return 1;
    }
    if (seccomp_load(ctx) < 0)
      return 1;
    seccomp_release(ctx);

    strcpy(fixed, *argv);
    execv(fixed, argv); // execve will change the first argument
#else
    execvp(*argv, argv);
#endif
  } else {
Ejemplo n.º 18
0
gboolean
tracker_seccomp_init (void)
{
	scmp_filter_ctx ctx;

	ctx = seccomp_init (SCMP_ACT_TRAP);
	if (ctx == NULL)
		return FALSE;

	/* Memory management */
	ALLOW_RULE (brk);
	ALLOW_RULE (mmap);
	ALLOW_RULE (mmap2);
	ALLOW_RULE (munmap);
	ALLOW_RULE (mremap);
	ALLOW_RULE (mprotect);
	ALLOW_RULE (madvise);
	ERROR_RULE (mlock, EPERM);
	ERROR_RULE (mlock2, EPERM);
	ERROR_RULE (munlock, EPERM);
	ERROR_RULE (mlockall, EPERM);
	ERROR_RULE (munlockall, EPERM);
	/* Process management */
	ALLOW_RULE (exit_group);
	ALLOW_RULE (getuid);
	ALLOW_RULE (getuid32);
	ALLOW_RULE (geteuid);
	ALLOW_RULE (geteuid32);
	ALLOW_RULE (getppid);
	ALLOW_RULE (gettid);
	ALLOW_RULE (exit);
	ALLOW_RULE (getrusage);
	ALLOW_RULE (getrlimit);
	/* Basic filesystem access */
	ALLOW_RULE (fstat);
	ALLOW_RULE (fstat64);
	ALLOW_RULE (stat);
	ALLOW_RULE (stat64);
	ALLOW_RULE (statfs);
	ALLOW_RULE (statfs64);
	ALLOW_RULE (lstat);
	ALLOW_RULE (lstat64);
	ALLOW_RULE (access);
	ALLOW_RULE (getdents);
	ALLOW_RULE (getdents64);
	ALLOW_RULE (readlink);
	ALLOW_RULE (readlinkat);
	ALLOW_RULE (utime);
	ALLOW_RULE (time);
	ALLOW_RULE (fsync);
	ALLOW_RULE (umask);
	/* Processes and threads */
	ALLOW_RULE (clone);
	ALLOW_RULE (futex);
	ALLOW_RULE (set_robust_list);
	ALLOW_RULE (rt_sigaction);
	ALLOW_RULE (rt_sigprocmask);
	ALLOW_RULE (sched_yield);
	ALLOW_RULE (sched_getaffinity);
	ALLOW_RULE (nanosleep);
	/* Main loops */
	ALLOW_RULE (poll);
	ALLOW_RULE (ppoll);
	ALLOW_RULE (fcntl);
	ALLOW_RULE (fcntl64);
	ALLOW_RULE (eventfd);
	ALLOW_RULE (eventfd2);
	ALLOW_RULE (pipe);
	ALLOW_RULE (pipe2);
	/* System */
	ALLOW_RULE (uname);
	ALLOW_RULE (sysinfo);
	ALLOW_RULE (prctl);
	ALLOW_RULE (getrandom);
	ALLOW_RULE (clock_gettime);
	ALLOW_RULE (clock_getres);
	ALLOW_RULE (gettimeofday);
	/* Descriptors */
	ALLOW_RULE (close);
	ALLOW_RULE (read);
	ALLOW_RULE (pread64);
	ALLOW_RULE (lseek);
	ALLOW_RULE (_llseek);
	ALLOW_RULE (fadvise64);
	ALLOW_RULE (write);
	ALLOW_RULE (writev);
	ALLOW_RULE (dup);
	/* Needed by some GStreamer modules doing crazy stuff, less
	 * scary thanks to the restriction below about sockets being
	 * local.
	 */
	ALLOW_RULE (connect);
	ALLOW_RULE (send);
	ALLOW_RULE (sendto);
	ALLOW_RULE (sendmsg);
	ALLOW_RULE (recv);
	ALLOW_RULE (recvmsg);
	ALLOW_RULE (recvfrom);
	ALLOW_RULE (getsockname);
	ALLOW_RULE (getpeername);
	ALLOW_RULE (shutdown);

	/* Special requirements for socket/socketpair, only on AF_UNIX/AF_LOCAL */
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
	                      SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
	                      SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair), 1,
	                      SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair), 1,
	                      SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) < 0)
		goto out;

	/* Special requirements for ioctl, allowed on stdout/stderr */
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
	                      SCMP_CMP(0, SCMP_CMP_EQ, 1)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
	                      SCMP_CMP(0, SCMP_CMP_EQ, 2)) < 0)
		goto out;

	/* Special requirements for open, allow O_RDONLY calls, but fail
	 * if write permissions are requested.
	 */
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
	                      SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EACCES), SCMP_SYS(open), 1,
	                      SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ERRNO (EACCES), SCMP_SYS(open), 1,
	                      SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) < 0)
		goto out;

	/* Special requirements for dup2/dup3, no fiddling with stdin/out/err */
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup2), 1,
	                      SCMP_CMP(1, SCMP_CMP_GT, 2)) < 0)
		goto out;
	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup3), 1,
	                      SCMP_CMP(1, SCMP_CMP_GT, 2)) < 0)
		goto out;

	g_debug ("Loading seccomp rules.");

	if (seccomp_load (ctx) >= 0)
		return TRUE;

out:
	g_critical ("Failed to load seccomp rules.");
	seccomp_release (ctx);
	return FALSE;
}