2
0

os-posix.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. #include "qemu/osdep.h"
  26. #include <sys/wait.h>
  27. #include <pwd.h>
  28. #include <grp.h>
  29. #include <libgen.h>
  30. #include "qemu-common.h"
  31. /* Needed early for CONFIG_BSD etc. */
  32. #include "net/slirp.h"
  33. #include "qemu-options.h"
  34. #include "qemu/error-report.h"
  35. #include "qemu/log.h"
  36. #include "sysemu/runstate.h"
  37. #include "qemu/cutils.h"
  38. #ifdef CONFIG_LINUX
  39. #include <sys/prctl.h>
  40. #endif
  41. /*
  42. * Must set all three of these at once.
  43. * Legal combinations are unset by name by uid
  44. */
  45. static struct passwd *user_pwd; /* NULL non-NULL NULL */
  46. static uid_t user_uid = (uid_t)-1; /* -1 -1 >=0 */
  47. static gid_t user_gid = (gid_t)-1; /* -1 -1 >=0 */
  48. static const char *chroot_dir;
  49. static int daemonize;
  50. static int daemon_pipe;
  51. void os_setup_early_signal_handling(void)
  52. {
  53. struct sigaction act;
  54. sigfillset(&act.sa_mask);
  55. act.sa_flags = 0;
  56. act.sa_handler = SIG_IGN;
  57. sigaction(SIGPIPE, &act, NULL);
  58. }
  59. static void termsig_handler(int signal, siginfo_t *info, void *c)
  60. {
  61. qemu_system_killed(info->si_signo, info->si_pid);
  62. }
  63. void os_setup_signal_handling(void)
  64. {
  65. struct sigaction act;
  66. memset(&act, 0, sizeof(act));
  67. act.sa_sigaction = termsig_handler;
  68. act.sa_flags = SA_SIGINFO;
  69. sigaction(SIGINT, &act, NULL);
  70. sigaction(SIGHUP, &act, NULL);
  71. sigaction(SIGTERM, &act, NULL);
  72. }
  73. /*
  74. * Find a likely location for support files using the location of the binary.
  75. * When running from the build tree this will be "$bindir/../pc-bios".
  76. * Otherwise, this is CONFIG_QEMU_DATADIR.
  77. *
  78. * The caller must use g_free() to free the returned data when it is
  79. * no longer required.
  80. */
  81. char *os_find_datadir(void)
  82. {
  83. g_autofree char *exec_dir = NULL;
  84. g_autofree char *dir = NULL;
  85. exec_dir = qemu_get_exec_dir();
  86. g_return_val_if_fail(exec_dir != NULL, NULL);
  87. dir = g_build_filename(exec_dir, "..", "pc-bios", NULL);
  88. if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
  89. return g_steal_pointer(&dir);
  90. }
  91. return g_strdup(CONFIG_QEMU_DATADIR);
  92. }
  93. void os_set_proc_name(const char *s)
  94. {
  95. #if defined(PR_SET_NAME)
  96. char name[16];
  97. if (!s)
  98. return;
  99. pstrcpy(name, sizeof(name), s);
  100. /* Could rewrite argv[0] too, but that's a bit more complicated.
  101. This simple way is enough for `top'. */
  102. if (prctl(PR_SET_NAME, name)) {
  103. error_report("unable to change process name: %s", strerror(errno));
  104. exit(1);
  105. }
  106. #else
  107. error_report("Change of process name not supported by your OS");
  108. exit(1);
  109. #endif
  110. }
  111. static bool os_parse_runas_uid_gid(const char *optarg)
  112. {
  113. unsigned long lv;
  114. const char *ep;
  115. uid_t got_uid;
  116. gid_t got_gid;
  117. int rc;
  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. rc = qemu_strtoul(ep + 1, 0, 0, &lv);
  124. got_gid = lv; /* overflow here is ID in C99 */
  125. if (rc || got_gid != lv || got_gid == (gid_t)-1) {
  126. return false;
  127. }
  128. user_pwd = NULL;
  129. user_uid = got_uid;
  130. user_gid = got_gid;
  131. return true;
  132. }
  133. /*
  134. * Parse OS specific command line options.
  135. * return 0 if option handled, -1 otherwise
  136. */
  137. int os_parse_cmd_args(int index, const char *optarg)
  138. {
  139. switch (index) {
  140. case QEMU_OPTION_runas:
  141. user_pwd = getpwnam(optarg);
  142. if (user_pwd) {
  143. user_uid = -1;
  144. user_gid = -1;
  145. } else if (!os_parse_runas_uid_gid(optarg)) {
  146. error_report("User \"%s\" doesn't exist"
  147. " (and is not <uid>:<gid>)",
  148. optarg);
  149. exit(1);
  150. }
  151. break;
  152. case QEMU_OPTION_chroot:
  153. chroot_dir = optarg;
  154. break;
  155. case QEMU_OPTION_daemonize:
  156. daemonize = 1;
  157. break;
  158. #if defined(CONFIG_LINUX)
  159. case QEMU_OPTION_enablefips:
  160. fips_set_state(true);
  161. break;
  162. #endif
  163. default:
  164. return -1;
  165. }
  166. return 0;
  167. }
  168. static void change_process_uid(void)
  169. {
  170. assert((user_uid == (uid_t)-1) || user_pwd == NULL);
  171. assert((user_uid == (uid_t)-1) ==
  172. (user_gid == (gid_t)-1));
  173. if (user_pwd || user_uid != (uid_t)-1) {
  174. gid_t intended_gid = user_pwd ? user_pwd->pw_gid : user_gid;
  175. uid_t intended_uid = user_pwd ? user_pwd->pw_uid : user_uid;
  176. if (setgid(intended_gid) < 0) {
  177. error_report("Failed to setgid(%d)", intended_gid);
  178. exit(1);
  179. }
  180. if (user_pwd) {
  181. if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
  182. error_report("Failed to initgroups(\"%s\", %d)",
  183. user_pwd->pw_name, user_pwd->pw_gid);
  184. exit(1);
  185. }
  186. } else {
  187. if (setgroups(1, &user_gid) < 0) {
  188. error_report("Failed to setgroups(1, [%d])",
  189. user_gid);
  190. exit(1);
  191. }
  192. }
  193. if (setuid(intended_uid) < 0) {
  194. error_report("Failed to setuid(%d)", intended_uid);
  195. exit(1);
  196. }
  197. if (setuid(0) != -1) {
  198. error_report("Dropping privileges failed");
  199. exit(1);
  200. }
  201. }
  202. }
  203. static void change_root(void)
  204. {
  205. if (chroot_dir) {
  206. if (chroot(chroot_dir) < 0) {
  207. error_report("chroot failed");
  208. exit(1);
  209. }
  210. if (chdir("/")) {
  211. error_report("not able to chdir to /: %s", strerror(errno));
  212. exit(1);
  213. }
  214. }
  215. }
  216. void os_daemonize(void)
  217. {
  218. if (daemonize) {
  219. pid_t pid;
  220. int fds[2];
  221. if (pipe(fds) == -1) {
  222. exit(1);
  223. }
  224. pid = fork();
  225. if (pid > 0) {
  226. uint8_t status;
  227. ssize_t len;
  228. close(fds[1]);
  229. do {
  230. len = read(fds[0], &status, 1);
  231. } while (len < 0 && errno == EINTR);
  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. } else if (pid < 0) {
  236. exit(1);
  237. }
  238. close(fds[0]);
  239. daemon_pipe = fds[1];
  240. qemu_set_cloexec(daemon_pipe);
  241. setsid();
  242. pid = fork();
  243. if (pid > 0) {
  244. exit(0);
  245. } else if (pid < 0) {
  246. exit(1);
  247. }
  248. umask(027);
  249. signal(SIGTSTP, SIG_IGN);
  250. signal(SIGTTOU, SIG_IGN);
  251. signal(SIGTTIN, SIG_IGN);
  252. }
  253. }
  254. void os_setup_post(void)
  255. {
  256. int fd = 0;
  257. if (daemonize) {
  258. if (chdir("/")) {
  259. error_report("not able to chdir to /: %s", strerror(errno));
  260. exit(1);
  261. }
  262. TFR(fd = qemu_open("/dev/null", O_RDWR));
  263. if (fd == -1) {
  264. exit(1);
  265. }
  266. }
  267. change_root();
  268. change_process_uid();
  269. if (daemonize) {
  270. uint8_t status = 0;
  271. ssize_t len;
  272. dup2(fd, 0);
  273. dup2(fd, 1);
  274. /* In case -D is given do not redirect stderr to /dev/null */
  275. if (!qemu_logfile) {
  276. dup2(fd, 2);
  277. }
  278. close(fd);
  279. do {
  280. len = write(daemon_pipe, &status, 1);
  281. } while (len < 0 && errno == EINTR);
  282. if (len != 1) {
  283. exit(1);
  284. }
  285. }
  286. }
  287. void os_set_line_buffering(void)
  288. {
  289. setvbuf(stdout, NULL, _IOLBF, 0);
  290. }
  291. bool is_daemonized(void)
  292. {
  293. return daemonize;
  294. }
  295. int os_mlock(void)
  296. {
  297. #ifdef HAVE_MLOCKALL
  298. int ret = 0;
  299. ret = mlockall(MCL_CURRENT | MCL_FUTURE);
  300. if (ret < 0) {
  301. error_report("mlockall: %s", strerror(errno));
  302. }
  303. return ret;
  304. #else
  305. return -ENOSYS;
  306. #endif
  307. }