1 /* 2 * os-posix.c 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * Copyright (c) 2010 Red Hat, Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 #include "qemu/osdep.h" 27 #include <sys/wait.h> 28 #include <pwd.h> 29 #include <grp.h> 30 #include <libgen.h> 31 32 #include "qemu/error-report.h" 33 #include "qemu/log.h" 34 #include "sysemu/runstate.h" 35 #include "qemu/cutils.h" 36 37 #ifdef CONFIG_LINUX 38 #include <sys/prctl.h> 39 #endif 40 41 42 void os_setup_early_signal_handling(void) 43 { 44 struct sigaction act; 45 sigfillset(&act.sa_mask); 46 act.sa_flags = 0; 47 act.sa_handler = SIG_IGN; 48 sigaction(SIGPIPE, &act, NULL); 49 } 50 51 static void termsig_handler(int signal, siginfo_t *info, void *c) 52 { 53 qemu_system_killed(info->si_signo, info->si_pid); 54 } 55 56 void os_setup_signal_handling(void) 57 { 58 struct sigaction act; 59 60 memset(&act, 0, sizeof(act)); 61 act.sa_sigaction = termsig_handler; 62 act.sa_flags = SA_SIGINFO; 63 sigaction(SIGINT, &act, NULL); 64 sigaction(SIGHUP, &act, NULL); 65 sigaction(SIGTERM, &act, NULL); 66 } 67 68 void os_set_proc_name(const char *s) 69 { 70 #if defined(PR_SET_NAME) 71 char name[16]; 72 if (!s) 73 return; 74 pstrcpy(name, sizeof(name), s); 75 /* Could rewrite argv[0] too, but that's a bit more complicated. 76 This simple way is enough for `top'. */ 77 if (prctl(PR_SET_NAME, name)) { 78 error_report("unable to change process name: %s", strerror(errno)); 79 exit(1); 80 } 81 #else 82 error_report("Change of process name not supported by your OS"); 83 exit(1); 84 #endif 85 } 86 87 88 /* 89 * Must set all three of these at once. 90 * Legal combinations are unset by name by uid 91 */ 92 static struct passwd *user_pwd; /* NULL non-NULL NULL */ 93 static uid_t user_uid = (uid_t)-1; /* -1 -1 >=0 */ 94 static gid_t user_gid = (gid_t)-1; /* -1 -1 >=0 */ 95 96 /* 97 * Prepare to change user ID. optarg can be one of 3 forms: 98 * - a username, in which case user ID will be changed to its uid, 99 * with primary and supplementary groups set up too; 100 * - a numeric uid, in which case only the uid will be set; 101 * - a pair of numeric uid:gid. 102 */ 103 bool os_set_runas(const char *optarg) 104 { 105 unsigned long lv; 106 const char *ep; 107 uid_t got_uid; 108 gid_t got_gid; 109 int rc; 110 111 user_pwd = getpwnam(optarg); 112 if (user_pwd) { 113 user_uid = -1; 114 user_gid = -1; 115 return true; 116 } 117 118 rc = qemu_strtoul(optarg, &ep, 0, &lv); 119 got_uid = lv; /* overflow here is ID in C99 */ 120 if (rc || *ep != ':' || got_uid != lv || got_uid == (uid_t)-1) { 121 return false; 122 } 123 124 rc = qemu_strtoul(ep + 1, 0, 0, &lv); 125 got_gid = lv; /* overflow here is ID in C99 */ 126 if (rc || got_gid != lv || got_gid == (gid_t)-1) { 127 return false; 128 } 129 130 user_pwd = NULL; 131 user_uid = got_uid; 132 user_gid = got_gid; 133 return true; 134 } 135 136 static void change_process_uid(void) 137 { 138 assert((user_uid == (uid_t)-1) || user_pwd == NULL); 139 assert((user_uid == (uid_t)-1) == 140 (user_gid == (gid_t)-1)); 141 142 if (user_pwd || user_uid != (uid_t)-1) { 143 gid_t intended_gid = user_pwd ? user_pwd->pw_gid : user_gid; 144 uid_t intended_uid = user_pwd ? user_pwd->pw_uid : user_uid; 145 if (setgid(intended_gid) < 0) { 146 error_report("Failed to setgid(%d)", intended_gid); 147 exit(1); 148 } 149 if (user_pwd) { 150 if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) { 151 error_report("Failed to initgroups(\"%s\", %d)", 152 user_pwd->pw_name, user_pwd->pw_gid); 153 exit(1); 154 } 155 } else { 156 if (setgroups(1, &user_gid) < 0) { 157 error_report("Failed to setgroups(1, [%d])", 158 user_gid); 159 exit(1); 160 } 161 } 162 if (setuid(intended_uid) < 0) { 163 error_report("Failed to setuid(%d)", intended_uid); 164 exit(1); 165 } 166 if (setuid(0) != -1) { 167 error_report("Dropping privileges failed"); 168 exit(1); 169 } 170 } 171 } 172 173 174 static const char *chroot_dir; 175 176 void os_set_chroot(const char *optarg) 177 { 178 chroot_dir = optarg; 179 } 180 181 static void change_root(void) 182 { 183 if (chroot_dir) { 184 if (chroot(chroot_dir) < 0) { 185 error_report("chroot failed"); 186 exit(1); 187 } 188 if (chdir("/")) { 189 error_report("not able to chdir to /: %s", strerror(errno)); 190 exit(1); 191 } 192 } 193 194 } 195 196 197 static int daemonize; 198 static int daemon_pipe; 199 200 bool is_daemonized(void) 201 { 202 return daemonize; 203 } 204 205 int os_set_daemonize(bool d) 206 { 207 daemonize = d; 208 return 0; 209 } 210 211 void os_daemonize(void) 212 { 213 if (daemonize) { 214 pid_t pid; 215 int fds[2]; 216 217 if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) { 218 exit(1); 219 } 220 221 pid = fork(); 222 if (pid > 0) { 223 uint8_t status; 224 ssize_t len; 225 226 close(fds[1]); 227 228 do { 229 len = read(fds[0], &status, 1); 230 } while (len < 0 && errno == EINTR); 231 232 /* only exit successfully if our child actually wrote 233 * a one-byte zero to our pipe, upon successful init */ 234 exit(len == 1 && status == 0 ? 0 : 1); 235 236 } else if (pid < 0) { 237 exit(1); 238 } 239 240 close(fds[0]); 241 daemon_pipe = fds[1]; 242 243 setsid(); 244 245 pid = fork(); 246 if (pid > 0) { 247 exit(0); 248 } else if (pid < 0) { 249 exit(1); 250 } 251 umask(027); 252 253 signal(SIGTSTP, SIG_IGN); 254 signal(SIGTTOU, SIG_IGN); 255 signal(SIGTTIN, SIG_IGN); 256 } 257 } 258 259 void os_setup_post(void) 260 { 261 int fd = 0; 262 263 if (daemonize) { 264 if (chdir("/")) { 265 error_report("not able to chdir to /: %s", strerror(errno)); 266 exit(1); 267 } 268 fd = RETRY_ON_EINTR(qemu_open_old("/dev/null", O_RDWR)); 269 if (fd == -1) { 270 exit(1); 271 } 272 } 273 274 change_root(); 275 change_process_uid(); 276 277 if (daemonize) { 278 uint8_t status = 0; 279 ssize_t len; 280 281 dup2(fd, 0); 282 dup2(fd, 1); 283 /* In case -D is given do not redirect stderr to /dev/null */ 284 if (!qemu_log_enabled()) { 285 dup2(fd, 2); 286 } 287 288 close(fd); 289 290 do { 291 len = write(daemon_pipe, &status, 1); 292 } while (len < 0 && errno == EINTR); 293 if (len != 1) { 294 exit(1); 295 } 296 } 297 } 298 299 void os_set_line_buffering(void) 300 { 301 setvbuf(stdout, NULL, _IOLBF, 0); 302 } 303 304 int os_mlock(void) 305 { 306 #ifdef HAVE_MLOCKALL 307 int ret = 0; 308 309 ret = mlockall(MCL_CURRENT | MCL_FUTURE); 310 if (ret < 0) { 311 error_report("mlockall: %s", strerror(errno)); 312 } 313 314 return ret; 315 #else 316 return -ENOSYS; 317 #endif 318 } 319