Commit 0858532ea93e0890bf13556f4ef3dc25d7636233

Authored by aliguori
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
... ...
... ... @@ -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();
... ...