|  |  | varnish-cache/bin/varnishd/mgt/mgt_jail.c | 
|---|
| 0 |  | /*- | 
| 1 |  |  * Copyright (c) 2015 Varnish Software AS | 
| 2 |  |  * All rights reserved. | 
| 3 |  |  * | 
| 4 |  |  * Author: Poul-Henning Kamp <phk@phk.freebsd.dk> | 
| 5 |  |  * | 
| 6 |  |  * SPDX-License-Identifier: BSD-2-Clause | 
| 7 |  |  * | 
| 8 |  |  * Redistribution and use in source and binary forms, with or without | 
| 9 |  |  * modification, are permitted provided that the following conditions | 
| 10 |  |  * are met: | 
| 11 |  |  * 1. Redistributions of source code must retain the above copyright | 
| 12 |  |  *    notice, this list of conditions and the following disclaimer. | 
| 13 |  |  * 2. Redistributions in binary form must reproduce the above copyright | 
| 14 |  |  *    notice, this list of conditions and the following disclaimer in the | 
| 15 |  |  *    documentation and/or other materials provided with the distribution. | 
| 16 |  |  * | 
| 17 |  |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 
| 18 |  |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
| 19 |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
| 20 |  |  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | 
| 21 |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
| 22 |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
| 23 |  |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
| 24 |  |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
| 25 |  |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
| 26 |  |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
| 27 |  |  * SUCH DAMAGE. | 
| 28 |  |  * | 
| 29 |  |  * Jailing | 
| 30 |  |  * | 
| 31 |  |  */ | 
| 32 |  |  | 
| 33 |  | #include "config.h" | 
| 34 |  |  | 
| 35 |  | #include <fcntl.h> | 
| 36 |  | #include <stdio.h> | 
| 37 |  | #include <stdlib.h> | 
| 38 |  | #include <string.h> | 
| 39 |  | #include <unistd.h> | 
| 40 |  | #include <sys/stat.h> | 
| 41 |  | //lint -efile(766, sys/statvfs.h) | 
| 42 |  | #include <sys/statvfs.h> | 
| 43 |  |  | 
| 44 |  | #include "mgt/mgt.h" | 
| 45 |  | #include "common/heritage.h" | 
| 46 |  | #include "vav.h" | 
| 47 |  |  | 
| 48 |  | /********************************************************************** | 
| 49 |  |  * A "none" jail implementation which doesn't do anything. | 
| 50 |  |  */ | 
| 51 |  |  | 
| 52 |  | static int v_matchproto_(jail_init_f) | 
| 53 | 11121 | vjn_init(char **args) | 
| 54 |  | { | 
| 55 | 11121 |         if (args != NULL && *args != NULL) | 
| 56 | 0 |                 ARGV_ERR("-jnone takes no arguments.\n"); | 
| 57 | 11121 |         return (0); | 
| 58 |  | } | 
| 59 |  |  | 
| 60 |  | static void v_matchproto_(jail_master_f) | 
| 61 | 678668 | vjn_master(enum jail_master_e jme) | 
| 62 |  | { | 
| 63 | 678668 |         (void)jme; | 
| 64 | 678668 | } | 
| 65 |  |  | 
| 66 |  | static void v_matchproto_(jail_subproc_f) | 
| 67 | 54648 | vjn_subproc(enum jail_subproc_e jse) | 
| 68 |  | { | 
| 69 | 54648 |         (void)jse; | 
| 70 | 54648 | } | 
| 71 |  |  | 
| 72 |  | static const struct jail_tech jail_tech_none = { | 
| 73 |  |         .magic =        JAIL_TECH_MAGIC, | 
| 74 |  |         .name =         "none", | 
| 75 |  |         .init =         vjn_init, | 
| 76 |  |         .master =       vjn_master, | 
| 77 |  |         .subproc =      vjn_subproc, | 
| 78 |  | }; | 
| 79 |  |  | 
| 80 |  | /**********************************************************************/ | 
| 81 |  |  | 
| 82 |  | static const struct jail_tech *vjt; | 
| 83 |  |  | 
| 84 |  | static const struct choice vj_choice[] = { | 
| 85 |  | #ifdef HAVE_SETPPRIV | 
| 86 |  |         { "solaris",    &jail_tech_solaris }, | 
| 87 |  | #endif | 
| 88 |  | #ifdef __linux__ | 
| 89 |  |         { "linux",      &jail_tech_linux }, | 
| 90 |  | #endif | 
| 91 |  |         { "unix",       &jail_tech_unix }, | 
| 92 |  |         { "none",       &jail_tech_none }, | 
| 93 |  |         { NULL,         NULL }, | 
| 94 |  | }; | 
| 95 |  |  | 
| 96 |  | void | 
| 97 | 11341 | VJ_Init(const char *j_arg) | 
| 98 |  | { | 
| 99 |  |         char **av; | 
| 100 |  |         int i; | 
| 101 |  |  | 
| 102 | 11341 |         if (j_arg != NULL) { | 
| 103 | 110 |                 av = VAV_Parse(j_arg, NULL, ARGV_COMMA); | 
| 104 | 110 |                 AN(av); | 
| 105 | 110 |                 if (av[0] != NULL) | 
| 106 | 0 |                         ARGV_ERR("-j argument: %s\n", av[0]); | 
| 107 | 110 |                 if (av[1] == NULL) | 
| 108 | 0 |                         ARGV_ERR("-j argument is empty\n"); | 
| 109 | 110 |                 vjt = MGT_Pick(vj_choice, av[1], "jail"); | 
| 110 | 110 |                 CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 111 | 110 |                 if (vjt->init(av + 2)) | 
| 112 | 0 |                         ARGV_EXIT; | 
| 113 | 110 |                 VAV_Free(av); | 
| 114 | 110 |         } else { | 
| 115 |  |                 /* | 
| 116 |  |                  * Go through list of jail technologies until one | 
| 117 |  |                  * succeeds, falling back to "none". | 
| 118 |  |                  */ | 
| 119 | 22352 |                 for (i = 0; vj_choice[i].name != NULL; i++) { | 
| 120 | 22352 |                         vjt = vj_choice[i].ptr; | 
| 121 | 22352 |                         CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 122 | 22352 |                         if (!vjt->init(NULL)) | 
| 123 | 11231 |                                 break; | 
| 124 | 11121 |                 } | 
| 125 |  |         } | 
| 126 | 11341 |         VSB_printf(vident, ",-j%s", vjt->name); | 
| 127 | 11341 | } | 
| 128 |  |  | 
| 129 |  | void | 
| 130 | 686599 | VJ_master(enum jail_master_e jme) | 
| 131 |  | { | 
| 132 | 686599 |         CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 133 | 686599 |         vjt->master(jme); | 
| 134 | 686599 | } | 
| 135 |  |  | 
| 136 |  | void | 
| 137 | 54956 | VJ_subproc(enum jail_subproc_e jse) | 
| 138 |  | { | 
| 139 | 54956 |         CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 140 | 54956 |         vjt->subproc(jse); | 
| 141 | 54956 | } | 
| 142 |  |  | 
| 143 |  | int | 
| 144 | 10846 | VJ_make_workdir(const char *dname, struct vsb *vsb) | 
| 145 |  | { | 
| 146 |  |         int i; | 
| 147 |  |  | 
| 148 | 10846 |         AN(dname); | 
| 149 | 10846 |         AN(vsb); | 
| 150 | 10846 |         CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 151 |  |  | 
| 152 | 10846 |         if (vjt->make_workdir != NULL) { | 
| 153 | 154 |                 i = vjt->make_workdir(dname, NULL, vsb); | 
| 154 | 154 |                 if (i) | 
| 155 | 0 |                         return (i); | 
| 156 | 154 |                 VJ_master(JAIL_MASTER_FILE); | 
| 157 | 154 |         } else { | 
| 158 | 10692 |                 VJ_master(JAIL_MASTER_FILE); | 
| 159 | 10692 |                 if (mkdir(dname, 0755) < 0 && errno != EEXIST) { | 
| 160 | 0 |                         VSB_printf(vsb, | 
| 161 |  |                             "Cannot create working directory '%s': %s\n", | 
| 162 | 0 |                             dname, VAS_errtxt(errno)); | 
| 163 | 0 |                         return (1); | 
| 164 |  |                 } | 
| 165 |  |         } | 
| 166 |  |  | 
| 167 | 10846 |         if (chdir(dname) < 0) { | 
| 168 | 0 |                 VSB_printf(vsb, "Cannot change to working directory '%s': %s\n", | 
| 169 | 0 |                     dname, VAS_errtxt(errno)); | 
| 170 | 0 |                 return (1); | 
| 171 |  |         } | 
| 172 |  |  | 
| 173 | 10846 |         i = open("_.testfile", O_RDWR|O_CREAT|O_EXCL, 0600); | 
| 174 | 10846 |         if (i < 0) { | 
| 175 | 0 |                 VSB_printf(vsb, "Cannot create test-file in %s (%s)\n" | 
| 176 |  |                     "Check permissions (or delete old directory)\n", | 
| 177 | 0 |                     dname, VAS_errtxt(errno)); | 
| 178 | 0 |                 return (1); | 
| 179 |  |         } | 
| 180 |  |  | 
| 181 |  | #ifdef ST_NOEXEC | 
| 182 |  |         struct statvfs vfs[1]; | 
| 183 |  |  | 
| 184 |  |         /* deliberately ignore fstatvfs errors */ | 
| 185 |  |         if (! fstatvfs(i, vfs) && vfs->f_flag & ST_NOEXEC) { | 
| 186 |  |                 closefd(&i); | 
| 187 |  |                 AZ(unlink("_.testfile")); | 
| 188 |  |                 VSB_printf(vsb, "Working directory %s (-n argument) " | 
| 189 |  |                     "cannot reside on a file system mounted noexec\n", dname); | 
| 190 |  |                 return (1); | 
| 191 |  |         } | 
| 192 |  | #endif | 
| 193 |  |  | 
| 194 | 10846 |         closefd(&i); | 
| 195 | 10846 |         AZ(unlink("_.testfile")); | 
| 196 | 10846 |         VJ_master(JAIL_MASTER_LOW); | 
| 197 | 10846 |         return (0); | 
| 198 | 10846 | } | 
| 199 |  |  | 
| 200 |  | int | 
| 201 | 38742 | VJ_make_subdir(const char *dname, const char *what, struct vsb *vsb) | 
| 202 |  | { | 
| 203 |  |         int e; | 
| 204 |  |  | 
| 205 | 38742 |         AN(dname); | 
| 206 | 38742 |         AN(what); | 
| 207 | 38742 |         AN(vsb); | 
| 208 | 38742 |         CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 209 | 38742 |         if (vjt->make_subdir != NULL) | 
| 210 | 462 |                 return (vjt->make_subdir(dname, what, vsb)); | 
| 211 |  |  | 
| 212 | 38280 |         VJ_master(JAIL_MASTER_FILE); | 
| 213 | 38280 |         if (mkdir(dname, 0755) < 0 && errno != EEXIST) { | 
| 214 | 0 |                 e = errno; | 
| 215 | 0 |                 VSB_printf(vsb, "Cannot create %s directory '%s': %s\n", | 
| 216 | 0 |                     what, dname, VAS_errtxt(e)); | 
| 217 | 0 |                 return (1); | 
| 218 |  |         } | 
| 219 | 38280 |         VJ_master(JAIL_MASTER_LOW); | 
| 220 | 38280 |         return (0); | 
| 221 | 38742 | } | 
| 222 |  |  | 
| 223 |  | void | 
| 224 | 37235 | VJ_unlink(const char *fname, int ignore_enoent) | 
| 225 |  | { | 
| 226 | 37235 |         VJ_master(JAIL_MASTER_FILE); | 
| 227 | 37235 |         if (unlink(fname)) { | 
| 228 | 3223 |                 if (errno != ENOENT || !ignore_enoent) | 
| 229 | 0 |                     fprintf(stderr, "Could not delete '%s': %s\n", | 
| 230 | 0 |                         fname, strerror(errno)); | 
| 231 | 3223 |         } | 
| 232 | 37235 |         VJ_master(JAIL_MASTER_LOW); | 
| 233 | 37235 | } | 
| 234 |  |  | 
| 235 |  | void | 
| 236 | 3399 | VJ_rmdir(const char *dname) | 
| 237 |  | { | 
| 238 | 3399 |         VJ_master(JAIL_MASTER_FILE); | 
| 239 | 3399 |         if (rmdir(dname)) { | 
| 240 | 22 |                 fprintf(stderr, "Could not rmdir '%s': %s\n", | 
| 241 | 11 |                     dname, strerror(errno)); | 
| 242 | 11 |         } | 
| 243 | 3399 |         VJ_master(JAIL_MASTER_LOW); | 
| 244 | 3399 | } | 
| 245 |  |  | 
| 246 |  | void | 
| 247 | 32824 | VJ_fix_fd(int fd, enum jail_fixfd_e what) | 
| 248 |  | { | 
| 249 |  |  | 
| 250 | 32824 |         CHECK_OBJ_NOTNULL(vjt, JAIL_TECH_MAGIC); | 
| 251 | 32824 |         if (vjt->fixfd != NULL) | 
| 252 | 495 |                 vjt->fixfd(fd, what); | 
| 253 | 32824 | } |