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(); | ... | ... |