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,6 +1161,14 @@ character to Control-t.
1161 @item -echr 20 1161 @item -echr 20
1162 @end table 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 @end table 1172 @end table
1165 1173
1166 @c man end 1174 @c man end
@@ -52,6 +52,7 @@ @@ -52,6 +52,7 @@
52 #include <zlib.h> 52 #include <zlib.h>
53 53
54 #ifndef _WIN32 54 #ifndef _WIN32
  55 +#include <pwd.h>
55 #include <sys/times.h> 56 #include <sys/times.h>
56 #include <sys/wait.h> 57 #include <sys/wait.h>
57 #include <termios.h> 58 #include <termios.h>
@@ -4075,6 +4076,10 @@ static void help(int exitcode) @@ -4075,6 +4076,10 @@ static void help(int exitcode)
4075 #endif 4076 #endif
4076 "-tb-size n set TB size\n" 4077 "-tb-size n set TB size\n"
4077 "-incoming p prepare for incoming migration, listen on port p\n" 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 "\n" 4083 "\n"
4079 "During emulation, the following keys are useful:\n" 4084 "During emulation, the following keys are useful:\n"
4080 "ctrl-alt-f toggle full screen\n" 4085 "ctrl-alt-f toggle full screen\n"
@@ -4192,6 +4197,8 @@ enum { @@ -4192,6 +4197,8 @@ enum {
4192 QEMU_OPTION_old_param, 4197 QEMU_OPTION_old_param,
4193 QEMU_OPTION_tb_size, 4198 QEMU_OPTION_tb_size,
4194 QEMU_OPTION_incoming, 4199 QEMU_OPTION_incoming,
  4200 + QEMU_OPTION_chroot,
  4201 + QEMU_OPTION_runas,
4195 }; 4202 };
4196 4203
4197 typedef struct QEMUOption { 4204 typedef struct QEMUOption {
@@ -4322,6 +4329,8 @@ static const QEMUOption qemu_options[] = { @@ -4322,6 +4329,8 @@ static const QEMUOption qemu_options[] = {
4322 #endif 4329 #endif
4323 { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, 4330 { "tb-size", HAS_ARG, QEMU_OPTION_tb_size },
4324 { "incoming", HAS_ARG, QEMU_OPTION_incoming }, 4331 { "incoming", HAS_ARG, QEMU_OPTION_incoming },
  4332 + { "chroot", HAS_ARG, QEMU_OPTION_chroot },
  4333 + { "runas", HAS_ARG, QEMU_OPTION_runas },
4325 { NULL }, 4334 { NULL },
4326 }; 4335 };
4327 4336
@@ -4632,6 +4641,10 @@ int main(int argc, char **argv, char **envp) @@ -4632,6 +4641,10 @@ int main(int argc, char **argv, char **envp)
4632 const char *pid_file = NULL; 4641 const char *pid_file = NULL;
4633 int autostart; 4642 int autostart;
4634 const char *incoming = NULL; 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 qemu_cache_utils_init(envp); 4649 qemu_cache_utils_init(envp);
4637 4650
@@ -5287,6 +5300,12 @@ int main(int argc, char **argv, char **envp) @@ -5287,6 +5300,12 @@ int main(int argc, char **argv, char **envp)
5287 case QEMU_OPTION_incoming: 5300 case QEMU_OPTION_incoming:
5288 incoming = optarg; 5301 incoming = optarg;
5289 break; 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,7 +5758,6 @@ int main(int argc, char **argv, char **envp)
5739 if (daemonize) { 5758 if (daemonize) {
5740 uint8_t status = 0; 5759 uint8_t status = 0;
5741 ssize_t len; 5760 ssize_t len;
5742 - int fd;  
5743 5761
5744 again1: 5762 again1:
5745 len = write(fds[1], &status, 1); 5763 len = write(fds[1], &status, 1);
@@ -5753,12 +5771,47 @@ int main(int argc, char **argv, char **envp) @@ -5753,12 +5771,47 @@ int main(int argc, char **argv, char **envp)
5753 TFR(fd = open("/dev/null", O_RDWR)); 5771 TFR(fd = open("/dev/null", O_RDWR));
5754 if (fd == -1) 5772 if (fd == -1)
5755 exit(1); 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 main_loop(); 5817 main_loop();