Commit 0858532ea93e0890bf13556f4ef3dc25d7636233
1 parent
8290edda
chroot and change user support (Nolan)
Resent with fixed formatting. This patch adds two new command line options: -chroot <dir> -runas <user> This is useful for running qemu as an unprivileged user in a chroot jail. To avoid having to populate the jail, chrooting happens right before the start of guest execution. Signed-off-by: Nolan Leake <nolan@sigbus.net> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6652 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
66 additions
and
5 deletions
qemu-doc.texi
| ... | ... | @@ -1161,6 +1161,14 @@ character to Control-t. |
| 1161 | 1161 | @item -echr 20 |
| 1162 | 1162 | @end table |
| 1163 | 1163 | |
| 1164 | +@item -chroot dir | |
| 1165 | +Immediately before starting guest execution, chroot to the specified | |
| 1166 | +directory. Especially useful in combination with -runas. | |
| 1167 | + | |
| 1168 | +@item -runas user | |
| 1169 | +Immediately before starting guest execution, drop root privileges, switching | |
| 1170 | +to the specified user. | |
| 1171 | + | |
| 1164 | 1172 | @end table |
| 1165 | 1173 | |
| 1166 | 1174 | @c man end | ... | ... |
vl.c
| ... | ... | @@ -52,6 +52,7 @@ |
| 52 | 52 | #include <zlib.h> |
| 53 | 53 | |
| 54 | 54 | #ifndef _WIN32 |
| 55 | +#include <pwd.h> | |
| 55 | 56 | #include <sys/times.h> |
| 56 | 57 | #include <sys/wait.h> |
| 57 | 58 | #include <termios.h> |
| ... | ... | @@ -4075,6 +4076,10 @@ static void help(int exitcode) |
| 4075 | 4076 | #endif |
| 4076 | 4077 | "-tb-size n set TB size\n" |
| 4077 | 4078 | "-incoming p prepare for incoming migration, listen on port p\n" |
| 4079 | +#ifndef _WIN32 | |
| 4080 | + "-chroot dir Chroot to dir just before starting the VM.\n" | |
| 4081 | + "-runas user Change to user id user just before starting the VM.\n" | |
| 4082 | +#endif | |
| 4078 | 4083 | "\n" |
| 4079 | 4084 | "During emulation, the following keys are useful:\n" |
| 4080 | 4085 | "ctrl-alt-f toggle full screen\n" |
| ... | ... | @@ -4192,6 +4197,8 @@ enum { |
| 4192 | 4197 | QEMU_OPTION_old_param, |
| 4193 | 4198 | QEMU_OPTION_tb_size, |
| 4194 | 4199 | QEMU_OPTION_incoming, |
| 4200 | + QEMU_OPTION_chroot, | |
| 4201 | + QEMU_OPTION_runas, | |
| 4195 | 4202 | }; |
| 4196 | 4203 | |
| 4197 | 4204 | typedef struct QEMUOption { |
| ... | ... | @@ -4322,6 +4329,8 @@ static const QEMUOption qemu_options[] = { |
| 4322 | 4329 | #endif |
| 4323 | 4330 | { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, |
| 4324 | 4331 | { "incoming", HAS_ARG, QEMU_OPTION_incoming }, |
| 4332 | + { "chroot", HAS_ARG, QEMU_OPTION_chroot }, | |
| 4333 | + { "runas", HAS_ARG, QEMU_OPTION_runas }, | |
| 4325 | 4334 | { NULL }, |
| 4326 | 4335 | }; |
| 4327 | 4336 | |
| ... | ... | @@ -4632,6 +4641,10 @@ int main(int argc, char **argv, char **envp) |
| 4632 | 4641 | const char *pid_file = NULL; |
| 4633 | 4642 | int autostart; |
| 4634 | 4643 | const char *incoming = NULL; |
| 4644 | + int fd; | |
| 4645 | + struct passwd *pwd; | |
| 4646 | + const char *chroot_dir = NULL; | |
| 4647 | + const char *run_as = NULL; | |
| 4635 | 4648 | |
| 4636 | 4649 | qemu_cache_utils_init(envp); |
| 4637 | 4650 | |
| ... | ... | @@ -5287,6 +5300,12 @@ int main(int argc, char **argv, char **envp) |
| 5287 | 5300 | case QEMU_OPTION_incoming: |
| 5288 | 5301 | incoming = optarg; |
| 5289 | 5302 | break; |
| 5303 | + case QEMU_OPTION_chroot: | |
| 5304 | + chroot_dir = optarg; | |
| 5305 | + break; | |
| 5306 | + case QEMU_OPTION_runas: | |
| 5307 | + run_as = optarg; | |
| 5308 | + break; | |
| 5290 | 5309 | } |
| 5291 | 5310 | } |
| 5292 | 5311 | } |
| ... | ... | @@ -5739,7 +5758,6 @@ int main(int argc, char **argv, char **envp) |
| 5739 | 5758 | if (daemonize) { |
| 5740 | 5759 | uint8_t status = 0; |
| 5741 | 5760 | ssize_t len; |
| 5742 | - int fd; | |
| 5743 | 5761 | |
| 5744 | 5762 | again1: |
| 5745 | 5763 | len = write(fds[1], &status, 1); |
| ... | ... | @@ -5753,12 +5771,47 @@ int main(int argc, char **argv, char **envp) |
| 5753 | 5771 | TFR(fd = open("/dev/null", O_RDWR)); |
| 5754 | 5772 | if (fd == -1) |
| 5755 | 5773 | exit(1); |
| 5774 | + } | |
| 5756 | 5775 | |
| 5757 | - dup2(fd, 0); | |
| 5758 | - dup2(fd, 1); | |
| 5759 | - dup2(fd, 2); | |
| 5776 | +#ifndef _WIN32 | |
| 5777 | + if (run_as) { | |
| 5778 | + pwd = getpwnam(run_as); | |
| 5779 | + if (!pwd) { | |
| 5780 | + fprintf(stderr, "User \"%s\" doesn't exist\n", run_as); | |
| 5781 | + exit(1); | |
| 5782 | + } | |
| 5783 | + } | |
| 5784 | + | |
| 5785 | + if (chroot_dir) { | |
| 5786 | + if (chroot(chroot_dir) < 0) { | |
| 5787 | + fprintf(stderr, "chroot failed\n"); | |
| 5788 | + exit(1); | |
| 5789 | + } | |
| 5790 | + chdir("/"); | |
| 5791 | + } | |
| 5792 | + | |
| 5793 | + if (run_as) { | |
| 5794 | + if (setgid(pwd->pw_gid) < 0) { | |
| 5795 | + fprintf(stderr, "Failed to setgid(%d)\n", pwd->pw_gid); | |
| 5796 | + exit(1); | |
| 5797 | + } | |
| 5798 | + if (setuid(pwd->pw_uid) < 0) { | |
| 5799 | + fprintf(stderr, "Failed to setuid(%d)\n", pwd->pw_uid); | |
| 5800 | + exit(1); | |
| 5801 | + } | |
| 5802 | + if (setuid(0) != -1) { | |
| 5803 | + fprintf(stderr, "Dropping privileges failed\n"); | |
| 5804 | + exit(1); | |
| 5805 | + } | |
| 5806 | + } | |
| 5807 | +#endif | |
| 5808 | + | |
| 5809 | + if (daemonize) { | |
| 5810 | + dup2(fd, 0); | |
| 5811 | + dup2(fd, 1); | |
| 5812 | + dup2(fd, 2); | |
| 5760 | 5813 | |
| 5761 | - close(fd); | |
| 5814 | + close(fd); | |
| 5762 | 5815 | } |
| 5763 | 5816 | |
| 5764 | 5817 | main_loop(); | ... | ... |