ksgi
/
sandbox-capsicum.c
210 строк · 4.9 Кб
1/* $Id$ */
2/*
3* Copyright (c) 2014 Baptiste Daroussin <bapt@freebsd.org>
4* Copyright (c) 2015--2016 Kristaps Dzonsons <kristaps@bsd.lv>
5*
6* Permission to use, copy, modify, and distribute this software for any
7* purpose with or without fee is hereby granted, provided that the above
8* copyright notice and this permission notice appear in all copies.
9*
10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18#include "config.h"19
20#if HAVE_CAPSICUM21
22#include <sys/resource.h>23#include <sys/capsicum.h>24
25#include <assert.h>26#include <unistd.h>27#include <errno.h>28#include <stdarg.h>29#include <stdlib.h>30
31#include "kcgi.h"32#include "extern.h"33
34static int35ksandbox_capsicum_init_control(int worker, int fdfiled, int fdaccept)36{
37int rc;38struct rlimit rl_zero;39cap_rights_t rights;40
41cap_rights_init(&rights);42
43/*44* If we have old-style accept FastCGI sockets, then mark us as
45* accepting on it.
46* XXX: the CAP_READ and CAP_WRITE are necessary because they're
47* required by descriptors we create from the accept().
48* The new-style passing of descriptors is easier.
49*/
50
51if (fdaccept != -1) {52cap_rights_init(&rights,53CAP_EVENT, CAP_FCNTL, CAP_ACCEPT,54CAP_READ, CAP_WRITE);55if (cap_rights_limit(fdaccept, &rights) < 0 &&56errno != ENOSYS) {57kutil_warn(NULL, NULL, "cap_rights_limit");58return 0;59}60} else {61assert(fdfiled != -1);62cap_rights_init(&rights, CAP_EVENT,63CAP_FCNTL, CAP_READ, CAP_WRITE);64if (cap_rights_limit(fdfiled, &rights) < 0 &&65errno != ENOSYS) {66kutil_warn(NULL, NULL, "cap_rights_limit");67return 0;68}69}70
71/* Always pass through write-only stderr. */72
73cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT);74if (cap_rights_limit(STDERR_FILENO, &rights) < 0 &&75errno != ENOSYS) {76kutil_warn(NULL, NULL, "cap_rights_limit");77return 0;78}79
80/* Interface to worker. */81
82cap_rights_init(&rights, CAP_EVENT,83CAP_FCNTL, CAP_READ, CAP_WRITE);84if (cap_rights_limit(worker, &rights) < 0 &&85errno != ENOSYS) {86kutil_warn(NULL, NULL, "cap_rights_limit");87return 0;88}89
90rl_zero.rlim_cur = rl_zero.rlim_max = 0;91if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1) {92kutil_warn(NULL, NULL, "setrlimit");93return 0;94} else if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1) {95kutil_warn(NULL, NULL, "setrlimit");96return 0;97}98
99rc = cap_enter();100if (rc && errno != ENOSYS) {101kutil_warn(NULL, NULL, "cap_enter");102rc = 0;103} else104rc = 1;105
106return rc;107}
108
109static int110ksandbox_capsicum_init_worker(int fd1, int fd2)111{
112int rc;113struct rlimit rl_zero;114cap_rights_t rights;115
116cap_rights_init(&rights);117
118/*119* Test for EBADF because STDIN_FILENO is usually closed by the
120* caller.
121*/
122
123cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_FSTAT);124if (cap_rights_limit(STDIN_FILENO, &rights) < 0 &&125errno != ENOSYS && errno != EBADF) {126kutil_warn(NULL, NULL, "cap_rights_limit");127return 0;128}129
130cap_rights_init(&rights, CAP_EVENT, CAP_WRITE, CAP_FSTAT);131if (cap_rights_limit(STDERR_FILENO, &rights) < 0 &&132errno != ENOSYS) {133kutil_warn(NULL, NULL, "cap_rights_limit");134return 0;135}136
137/* Only do thesee if the descriptors are valid. */138
139cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE, CAP_FSTAT);140if (fd1 != -1 && cap_rights_limit(fd1, &rights) < 0 &&141errno != ENOSYS) {142kutil_warn(NULL, NULL, "cap_rights_limit");143return 0;144}145if (fd2 != -1 && cap_rights_limit(fd2, &rights) < 0 &&146errno != ENOSYS) {147kutil_warn(NULL, NULL, "cap_rights_limit");148return 0;149}150
151rl_zero.rlim_cur = rl_zero.rlim_max = 0;152
153#if 0154/* Don't run this: if we use openlog, it will fail. */155
156if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1) {157kutil_warn(NULL, NULL, "setrlimit");158return 0;159}160#endif161
162if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1) {163kutil_warn(NULL, NULL, "setrlimit");164return 0;165} else if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1) {166kutil_warn(NULL, NULL, "setrlimit");167return 0;168}169
170rc = cap_enter();171if (rc && errno != ENOSYS) {172kutil_warn(NULL, NULL, "cap_enter");173rc = 0;174} else175rc = 1;176
177return rc;178}
179
180int
181ksandbox_capsicum_init_child(enum sandtype type,182int fd1, int fd2, int fdfiled, int fdaccept)183{
184int rc;185
186switch (type) {187case SAND_WORKER:188rc = ksandbox_capsicum_init_worker(fd1, fd2);189break;190case SAND_CONTROL_OLD:191assert(fd2 == -1);192rc = ksandbox_capsicum_init_control193(fd1, fdfiled, fdaccept);194break;195case SAND_CONTROL_NEW:196assert(fd2 == -1);197rc = ksandbox_capsicum_init_control198(fd1, fdfiled, fdaccept);199break;200default:201abort();202}203
204if (!rc)205kutil_warnx(NULL, NULL, "capsicum sandbox failure");206
207return rc;208}
209
210#endif211