1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <spawn.h> 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <signal.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include "private/ScopedSignalBlocker.h" 39 #include "private/SigSetConverter.h" 40 41 enum Action { 42 kOpen, 43 kClose, 44 kDup2 45 }; 46 47 struct __posix_spawn_file_action { 48 __posix_spawn_file_action* next; 49 50 Action what; 51 int fd; 52 int new_fd; 53 char* path; 54 int flags; 55 mode_t mode; 56 57 void Do() { 58 if (what == kOpen) { 59 fd = open(path, flags, mode); 60 if (fd == -1) _exit(127); 61 // If it didn't land where we wanted it, move it. 62 if (fd != new_fd) { 63 if (dup2(fd, new_fd) == -1) _exit(127); 64 close(fd); 65 } 66 } else if (what == kClose) { 67 // Failure to close is ignored. 68 close(fd); 69 } else { 70 if (dup2(fd, new_fd) == -1) _exit(127); 71 } 72 } 73 }; 74 75 struct __posix_spawn_file_actions { 76 __posix_spawn_file_action* head; 77 __posix_spawn_file_action* last; 78 79 void Do() { 80 for (__posix_spawn_file_action* action = head; action != nullptr; action = action->next) { 81 action->Do(); 82 } 83 } 84 }; 85 86 struct __posix_spawnattr { 87 short flags; 88 pid_t pgroup; 89 sched_param schedparam; 90 int schedpolicy; 91 SigSetConverter sigmask; 92 SigSetConverter sigdefault; 93 }; 94 95 static void ApplyAttrs(short flags, const posix_spawnattr_t* attr) { 96 // POSIX: "If POSIX_SPAWN_SETSIGDEF is set ... signals in sigdefault ... 97 // shall be set to their default actions in the child process." 98 // POSIX: "Signals set to be caught by the calling process shall be 99 // set to the default action in the child process." 100 bool use_sigdefault = ((flags & POSIX_SPAWN_SETSIGDEF) != 0); 101 const struct sigaction64 default_sa = { .sa_handler = SIG_DFL }; 102 for (int s = 1; s < _NSIG; ++s) { 103 bool reset = false; 104 if (use_sigdefault && sigismember64(&(*attr)->sigdefault.sigset64, s)) { 105 reset = true; 106 } else { 107 struct sigaction64 current; 108 if (sigaction64(s, nullptr, ¤t) == -1) _exit(127); 109 reset = (current.sa_handler != SIG_IGN && current.sa_handler != SIG_DFL); 110 } 111 if (reset && sigaction64(s, &default_sa, nullptr) == -1) _exit(127); 112 } 113 114 if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && setpgid(0, (*attr)->pgroup) == -1) _exit(127); 115 if ((flags & POSIX_SPAWN_SETSID) != 0 && setsid() == -1) _exit(127); 116 117 // POSIX_SPAWN_SETSCHEDULER overrides POSIX_SPAWN_SETSCHEDPARAM, but it is not an error 118 // to set both. 119 if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) { 120 if (sched_setscheduler(0, (*attr)->schedpolicy, &(*attr)->schedparam) == -1) _exit(127); 121 } else if ((flags & POSIX_SPAWN_SETSCHEDPARAM) != 0) { 122 if (sched_setparam(0, &(*attr)->schedparam) == -1) _exit(127); 123 } 124 125 if ((flags & POSIX_SPAWN_RESETIDS) != 0) { 126 if (seteuid(getuid()) == -1 || setegid(getgid()) == -1) _exit(127); 127 } 128 129 if ((flags & POSIX_SPAWN_SETSIGMASK) != 0) { 130 if (sigprocmask64(SIG_SETMASK, &(*attr)->sigmask.sigset64, nullptr)) _exit(127); 131 } 132 } 133 134 static int posix_spawn(pid_t* pid_ptr, 135 const char* path, 136 const posix_spawn_file_actions_t* actions, 137 const posix_spawnattr_t* attr, 138 char* const argv[], 139 char* const env[], 140 int exec_fn(const char* path, char* const argv[], char* const env[])) { 141 // See http://man7.org/linux/man-pages/man3/posix_spawn.3.html 142 // and http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html 143 144 ScopedSignalBlocker ssb; 145 146 short flags = attr ? (*attr)->flags : 0; 147 bool use_vfork = ((flags & POSIX_SPAWN_USEVFORK) != 0) || (actions == nullptr && flags == 0); 148 149 pid_t pid = use_vfork ? vfork() : fork(); 150 if (pid == -1) return errno; 151 152 if (pid == 0) { 153 // Child. 154 ApplyAttrs(flags, attr); 155 if (actions) (*actions)->Do(); 156 if ((flags & POSIX_SPAWN_SETSIGMASK) == 0) ssb.reset(); 157 exec_fn(path, argv, env ? env : environ); 158 _exit(127); 159 } 160 161 // Parent. 162 if (pid_ptr) *pid_ptr = pid; 163 return 0; 164 } 165 166 int posix_spawn(pid_t* pid, const char* path, const posix_spawn_file_actions_t* actions, 167 const posix_spawnattr_t* attr, char* const argv[], char* const env[]) { 168 return posix_spawn(pid, path, actions, attr, argv, env, execve); 169 } 170 171 int posix_spawnp(pid_t* pid, const char* file, const posix_spawn_file_actions_t* actions, 172 const posix_spawnattr_t* attr, char* const argv[], char* const env[]) { 173 return posix_spawn(pid, file, actions, attr, argv, env, execvpe); 174 } 175 176 int posix_spawnattr_init(posix_spawnattr_t* attr) { 177 *attr = reinterpret_cast<__posix_spawnattr*>(calloc(1, sizeof(__posix_spawnattr))); 178 return (*attr == nullptr) ? errno : 0; 179 } 180 181 int posix_spawnattr_destroy(posix_spawnattr_t* attr) { 182 free(*attr); 183 *attr = nullptr; 184 return 0; 185 } 186 187 int posix_spawnattr_setflags(posix_spawnattr_t* attr, short flags) { 188 if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF | 189 POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | 190 POSIX_SPAWN_USEVFORK | POSIX_SPAWN_SETSID)) != 0) { 191 return EINVAL; 192 } 193 (*attr)->flags = flags; 194 return 0; 195 } 196 197 int posix_spawnattr_getflags(const posix_spawnattr_t* attr, short* flags) { 198 *flags = (*attr)->flags; 199 return 0; 200 } 201 202 int posix_spawnattr_setpgroup(posix_spawnattr_t* attr, pid_t pgroup) { 203 (*attr)->pgroup = pgroup; 204 return 0; 205 } 206 207 int posix_spawnattr_getpgroup(const posix_spawnattr_t* attr, pid_t* pgroup) { 208 *pgroup = (*attr)->pgroup; 209 return 0; 210 } 211 212 int posix_spawnattr_setsigmask(posix_spawnattr_t* attr, const sigset_t* mask) { 213 (*attr)->sigmask.sigset = *mask; 214 return 0; 215 } 216 217 int posix_spawnattr_setsigmask64(posix_spawnattr_t* attr, const sigset64_t* mask) { 218 (*attr)->sigmask.sigset64 = *mask; 219 return 0; 220 } 221 222 int posix_spawnattr_getsigmask(const posix_spawnattr_t* attr, sigset_t* mask) { 223 *mask = (*attr)->sigmask.sigset; 224 return 0; 225 } 226 227 int posix_spawnattr_getsigmask64(const posix_spawnattr_t* attr, sigset64_t* mask) { 228 *mask = (*attr)->sigmask.sigset64; 229 return 0; 230 } 231 232 int posix_spawnattr_setsigdefault(posix_spawnattr_t* attr, const sigset_t* mask) { 233 (*attr)->sigdefault.sigset = *mask; 234 return 0; 235 } 236 237 int posix_spawnattr_setsigdefault64(posix_spawnattr_t* attr, const sigset64_t* mask) { 238 (*attr)->sigdefault.sigset64 = *mask; 239 return 0; 240 } 241 242 int posix_spawnattr_getsigdefault(const posix_spawnattr_t* attr, sigset_t* mask) { 243 *mask = (*attr)->sigdefault.sigset; 244 return 0; 245 } 246 247 int posix_spawnattr_getsigdefault64(const posix_spawnattr_t* attr, sigset64_t* mask) { 248 *mask = (*attr)->sigdefault.sigset64; 249 return 0; 250 } 251 252 int posix_spawnattr_setschedparam(posix_spawnattr_t* attr, const struct sched_param* param) { 253 (*attr)->schedparam = *param; 254 return 0; 255 } 256 257 int posix_spawnattr_getschedparam(const posix_spawnattr_t* attr, struct sched_param* param) { 258 *param = (*attr)->schedparam; 259 return 0; 260 } 261 262 int posix_spawnattr_setschedpolicy(posix_spawnattr_t* attr, int policy) { 263 (*attr)->schedpolicy = policy; 264 return 0; 265 } 266 267 int posix_spawnattr_getschedpolicy(const posix_spawnattr_t* attr, int* policy) { 268 *policy = (*attr)->schedpolicy; 269 return 0; 270 } 271 272 int posix_spawn_file_actions_init(posix_spawn_file_actions_t* actions) { 273 *actions = reinterpret_cast<__posix_spawn_file_actions*>(calloc(1, sizeof(**actions))); 274 return (*actions == nullptr) ? errno : 0; 275 } 276 277 int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* actions) { 278 __posix_spawn_file_action* a = (*actions)->head; 279 while (a) { 280 __posix_spawn_file_action* last = a; 281 a = a->next; 282 free(last->path); 283 free(last); 284 } 285 free(*actions); 286 *actions = nullptr; 287 return 0; 288 } 289 290 static int posix_spawn_add_file_action(posix_spawn_file_actions_t* actions, 291 Action what, 292 int fd, 293 int new_fd, 294 const char* path, 295 int flags, 296 mode_t mode) { 297 __posix_spawn_file_action* action = 298 reinterpret_cast<__posix_spawn_file_action*>(malloc(sizeof(*action))); 299 if (action == nullptr) return errno; 300 301 action->next = nullptr; 302 if (path != nullptr) { 303 action->path = strdup(path); 304 if (action->path == nullptr) { 305 free(action); 306 return errno; 307 } 308 } else { 309 action->path = nullptr; 310 } 311 action->what = what; 312 action->fd = fd; 313 action->new_fd = new_fd; 314 action->flags = flags; 315 action->mode = mode; 316 317 if ((*actions)->head == nullptr) { 318 (*actions)->head = (*actions)->last = action; 319 } else { 320 (*actions)->last->next = action; 321 (*actions)->last = action; 322 } 323 324 return 0; 325 } 326 327 int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* actions, 328 int fd, const char* path, int flags, mode_t mode) { 329 if (fd < 0) return EBADF; 330 return posix_spawn_add_file_action(actions, kOpen, -1, fd, path, flags, mode); 331 } 332 333 int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t* actions, int fd) { 334 if (fd < 0) return EBADF; 335 return posix_spawn_add_file_action(actions, kClose, fd, -1, nullptr, 0, 0); 336 } 337 338 int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* actions, int fd, int new_fd) { 339 if (fd < 0 || new_fd < 0) return EBADF; 340 return posix_spawn_add_file_action(actions, kDup2, fd, new_fd, nullptr, 0, 0); 341 } 342