Example #1
0
static int
ksandbox_capsicum_init_control(void *arg, int fd1, int fd2)
{
	int rc;
	struct rlimit	 rl_zero;
	cap_rights_t	 rights;

	cap_rights_init(&rights);

	cap_rights_init(&rights, CAP_EVENT, CAP_FCNTL, CAP_ACCEPT);
	if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && 
		 errno != ENOSYS) {
 		XWARN("cap_rights_limit: STDIN_FILENO");
		return(0);
	}

	cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT);
	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: STDERR_FILENO");
		return(0);
	}

	cap_rights_init(&rights, CAP_EVENT, 
		CAP_FCNTL, CAP_READ, CAP_WRITE);
	if (cap_rights_limit(fd1, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: internal socket");
		return(0);
	}

	rl_zero.rlim_cur = rl_zero.rlim_max = 0;

	if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) {
		XWARNX("setrlimit: rlimit_fsize");
		return(0);
	} else if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) {
		XWARNX("setrlimit: rlimit_nproc");
		return(0);
	}

	rc = cap_enter();
	if (0 != rc && errno != ENOSYS) {
		XWARN("cap_enter");
		rc = 0;
	} else
		rc = 1;

	return(rc);
}
int
ksandbox_seccomp_init_child(void *arg, enum sandtype type)
{
	struct rlimit rl_zero;
	int nnp_failed = 0;

	/* Set rlimits for completeness if possible. */
	rl_zero.rlim_cur = rl_zero.rlim_max = 0;
	if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
		XWARN("setrlimit(RLIMIT_FSIZE)");
#if 0
	/*
	 * Don't do like OpenSSH: we need to pass stuff back and forth
	 * over pipes, and this will prevent that from happening.
	 */
	if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
		XWARN("setrlimit(RLIMIT_NOFILE)");
#endif
	if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
		XWARN("setrlimit(RLIMIT_NPROC)");

#ifdef SANDBOX_SECCOMP_DEBUG
	ssh_sandbox_child_debugging();
#endif 

	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
		XWARN("prctl(PR_SET_NO_NEW_PRIVS)");
		nnp_failed = 1;
	}
	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 
		 SAND_WORKER != type ?
		 &preauth_prog_ctrl :
		 &preauth_prog_work) == -1)
		XWARN("prctl(PR_SET_SECCOMP)");
	else if (nnp_failed) {
		XWARNX("SECCOMP_MODE_FILTER activated but "
		    "PR_SET_NO_NEW_PRIVS failed");
		_exit(EXIT_FAILURE);
	}
	return(1);
}
Example #3
0
int
ksandbox_darwin_init_child(void *arg, enum sandtype type)
{
	int	 	 rc;
	char		*er;
	struct rlimit	 rl_zero;

	rc = SAND_WORKER == type ?
		sandbox_init(kSBXProfilePureComputation, 
			SANDBOX_NAMED, &er) :
		sandbox_init(kSBXProfileNoWrite, 
			SANDBOX_NAMED, &er);

	if (0 != rc) {
		XWARNX("sandbox_init: %s", er);
		sandbox_free_error(er);
		rc = 0;
	} else
		rc = 1;

	rl_zero.rlim_cur = rl_zero.rlim_max = 0;
#if 0
	/*
	 * FIXME: I've taken out the RLIMIT_NOFILE setrlimit() because
	 * it causes strange behaviour.  On Mac OS X, it fails with
	 * EPERM no matter what (the same code runs fine when not run as
	 * a CGI instance).
	 */
	if (-1 == setrlimit(RLIMIT_NOFILE, &rl_zero))
		XWARN("setrlimit: rlimit_fsize");
#endif
	if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero))
		XWARN("setrlimit: rlimit_fsize");
	if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero))
		XWARN("setrlimit: rlimit_nproc");

	return(rc);
}
Example #4
0
int
ksandbox_pledge_init_child(void *arg, enum sandtype type)
{
	const char *fl;

	fl = "stdio";
	if (SAND_CONTROL == type)
		fl = "stdio unix sendfd recvfd";

	if (-1 == pledge(fl, NULL)) {
		XWARN("pledge: %s",
			SAND_CONTROL == type ?
			"control" : "worker");
		return(0);
	}
	return(1);
}
Example #5
0
int
ksandbox_systrace_init_child(void *arg, enum sandtype type)
{
    struct systrace_sandbox *box = arg;

    if (NULL == arg) {
        XWARNX("systrace child passed null config");
        return(0);
    }

    signal(SIGCHLD, box->osigchld);
    if (kill(getpid(), SIGSTOP) == 0)
        return(1);

    XWARN("kill: SIGSTOP");
    return(0);
}
Example #6
0
static int
ksandbox_capsicum_init_control(void *arg, 
	int worker, int fdfiled, int fdaccept)
{
	int rc;
	struct rlimit	 rl_zero;
	cap_rights_t	 rights;

	cap_rights_init(&rights);

	if (-1 != fdaccept) {
		/*
		 * If we have old-style accept FastCGI sockets, then
		 * mark us as accepting on it.
		 */
		cap_rights_init(&rights, 
			CAP_EVENT, CAP_FCNTL, CAP_ACCEPT);
		if (cap_rights_limit(fdaccept, &rights) < 0 && 
			 errno != ENOSYS) {
			XWARN("cap_rights_limit: accept socket");
			return(0);
		}
	} else {
		/* New-style descriptor-passing socket. */
		assert(-1 != fdfiled);
		cap_rights_init(&rights, CAP_EVENT, 
			CAP_FCNTL, CAP_READ, CAP_WRITE);
		if (cap_rights_limit(fdfiled, &rights) < 0 && 
			 errno != ENOSYS) {
			XWARN("cap_rights_limit: descriptor socket");
			return(0);
		}
	}

	/* Always pass through write-only stderr. */
	cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT);
	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: STDERR_FILENO");
		return(0);
	}

	/* Interface to worker. */
	cap_rights_init(&rights, CAP_EVENT, 
		CAP_FCNTL, CAP_READ, CAP_WRITE);
	if (cap_rights_limit(worker, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: internal socket");
		return(0);
	}

	rl_zero.rlim_cur = rl_zero.rlim_max = 0;
	if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) {
		XWARNX("setrlimit: rlimit_fsize");
		return(0);
	} else if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) {
		XWARNX("setrlimit: rlimit_nproc");
		return(0);
	}

	rc = cap_enter();
	if (0 != rc && errno != ENOSYS) {
		XWARN("cap_enter");
		rc = 0;
	} else
		rc = 1;

	return(rc);
}
Example #7
0
static int
ksandbox_capsicum_init_worker(void *arg, int fd1, int fd2)
{
	int rc;
	struct rlimit	 rl_zero;
	cap_rights_t	 rights;

	cap_rights_init(&rights);

	/* 
	 * Test for EBADF because STDIN_FILENO is usually closed by the
	 * caller.
	 */
	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_FSTAT);
	if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && 
		 errno != ENOSYS && errno != EBADF) {
 		XWARN("cap_rights_limit: STDIN_FILENO");
		return(0);
	}

	cap_rights_init(&rights, CAP_EVENT, CAP_WRITE, CAP_FSTAT);
	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: STDERR_FILENO");
		return(0);
	}

	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE, CAP_FSTAT);
	if (-1 != fd1 && cap_rights_limit(fd1, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: internal socket");
		return(0);
	}
	if (-1 != fd2 && cap_rights_limit(fd2, &rights) < 0 && 
		 errno != ENOSYS) {
		XWARN("cap_rights_limit: internal socket");
		return(0);
	}

	rl_zero.rlim_cur = rl_zero.rlim_max = 0;

	if (-1 == setrlimit(RLIMIT_NOFILE, &rl_zero)) {
		XWARNX("setrlimit: rlimit_fsize");
		return(0);
	} else if (-1 == setrlimit(RLIMIT_FSIZE, &rl_zero)) {
		XWARNX("setrlimit: rlimit_fsize");
		return(0);
	} else if (-1 == setrlimit(RLIMIT_NPROC, &rl_zero)) {
		XWARNX("setrlimit: rlimit_nproc");
		return(0);
	}

	rc = cap_enter();
	if (0 != rc && errno != ENOSYS) {
		XWARN("cap_enter");
		rc = 0;
	} else
		rc = 1;

	return(rc);
}
Example #8
0
int
ksandbox_systrace_init_parent(void *arg, enum sandtype type, pid_t child)
{
    struct systrace_sandbox *box = arg;
    int		dev, i, j, found, st, rc;
    pid_t		pid;
    struct systrace_policy policy;
    const struct systrace_preauth *preauth;

    assert(NULL != arg);

    preauth = SAND_WORKER != type ?
              preauth_control : preauth_worker;

    rc = 0;

    /*
     * Wait for the child to send itself a SIGSTOP.
     * When we receive it, the child is waiting to be sandboxed.
     */
    do
        pid = waitpid(child, &st, WUNTRACED);
    while (pid == -1 && errno == EINTR);

    if (-1 == pid) {
        XWARN("waitpid");
        return(0);
    }

    /* Catch if it exits. */
    signal(SIGCHLD, box->osigchld);

    if ( ! WIFSTOPPED(st)) {
        if (WIFSIGNALED(st)) {
            XWARNX("child signal %d", WTERMSIG(st));
            return(0);
        } else if (WIFEXITED(st)) {
            XWARNX("child exit %d", WEXITSTATUS(st));
            return(0);
        }
        XWARNX("child not stopped");
        return(0);
    }

    box->child_pid = child;

    /* Set up systracing of child */
    if ((dev = open("/dev/systrace", O_RDONLY)) == -1) {
        if (ENXIO == errno) {
            XWARN("open: /dev/systrace (mounted nodev?)");
            goto out;
        }
        XWARN("open: /dev/systrace");
        goto out;
    }

    if (ioctl(dev, STRIOCCLONE, &box->systrace_fd) == -1) {
        XWARN("ioctl: STRIOCCLONE");
        close(dev);
        goto out;
    }

    close(dev);

    if (ioctl(box->systrace_fd, STRIOCATTACH, &child) == -1) {
        XWARN("ioctl: STRIOCATTACH");
        goto out;
    }

    /* Allocate and assign policy */
    memset(&policy, 0, sizeof(policy));
    policy.strp_op = SYSTR_POLICY_NEW;
    policy.strp_maxents = SYS_MAXSYSCALL;
    if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1) {
        XWARN("ioctl: STRIOCPOLICY (new)");
        goto out;
    }

    policy.strp_op = SYSTR_POLICY_ASSIGN;
    policy.strp_pid = box->child_pid;
    if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1) {
        XWARN("ioctl: STRIOCPOLICY (assign)");
        goto out;
    }

    /* Set per-syscall policy */
    for (i = 0; i < SYS_MAXSYSCALL; i++) {
        found = 0;
        for (j = 0; preauth[j].syscall != -1; j++) {
            if (preauth[j].syscall == i) {
                found = 1;
                break;
            }
        }
        policy.strp_op = SYSTR_POLICY_MODIFY;
        policy.strp_code = i;
        policy.strp_policy = found ?
                             preauth[j].action : SYSTR_POLICY_KILL;
        if (ioctl(box->systrace_fd, STRIOCPOLICY, &policy) == -1) {
            XWARN("ioctl: STRIOCPOLICY (modify)");
            goto out;
        }
    }

    rc = 1;
out:
    /* Signal the child to start running */
    if (kill(box->child_pid, SIGCONT) == 0)
        return(rc);

    XWARN("kill: SIGCONT");
    return(0);
}