From 8aeb36e8f6d7eaa9cafc970b700414205743b258 Mon Sep 17 00:00:00 2001 From: Philip Sanderson Date: Thu, 20 Jan 2011 21:37:28 -0600 Subject: lguest: --username and --chroot options I've attached a patch which implements dropping to privileges and chrooting to a directory. Signed-off-by: Rusty Russell --- Documentation/lguest/lguest.c | 50 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'Documentation') diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index dc73bc54..f64b85b 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -39,6 +39,9 @@ #include #include #include +#include +#include + #include #include #include @@ -1872,6 +1875,8 @@ static struct option opts[] = { { "block", 1, NULL, 'b' }, { "rng", 0, NULL, 'r' }, { "initrd", 1, NULL, 'i' }, + { "username", 1, NULL, 'u' }, + { "chroot", 1, NULL, 'c' }, { NULL }, }; static void usage(void) @@ -1894,6 +1899,12 @@ int main(int argc, char *argv[]) /* If they specify an initrd file to load. */ const char *initrd_name = NULL; + /* Password structure for initgroups/setres[gu]id */ + struct passwd *user_details = NULL; + + /* Directory to chroot to */ + char *chroot_path = NULL; + /* Save the args: we "reboot" by execing ourselves again. */ main_args = argv; @@ -1950,6 +1961,14 @@ int main(int argc, char *argv[]) case 'i': initrd_name = optarg; break; + case 'u': + user_details = getpwnam(optarg); + if (!user_details) + err(1, "getpwnam failed, incorrect username?"); + break; + case 'c': + chroot_path = optarg; + break; default: warnx("Unknown argument %s", argv[optind]); usage(); @@ -2021,6 +2040,37 @@ int main(int argc, char *argv[]) /* If we exit via err(), this kills all the threads, restores tty. */ atexit(cleanup_devices); + /* If requested, chroot to a directory */ + if (chroot_path) { + if (chroot(chroot_path) != 0) + err(1, "chroot(\"%s\") failed", chroot_path); + + if (chdir("/") != 0) + err(1, "chdir(\"/\") failed"); + + verbose("chroot done\n"); + } + + /* If requested, drop privileges */ + if (user_details) { + uid_t u; + gid_t g; + + u = user_details->pw_uid; + g = user_details->pw_gid; + + if (initgroups(user_details->pw_name, g) != 0) + err(1, "initgroups failed"); + + if (setresgid(g, g, g) != 0) + err(1, "setresgid failed"); + + if (setresuid(u, u, u) != 0) + err(1, "setresuid failed"); + + verbose("Dropping privileges completed\n"); + } + /* Finally, run the Guest. This doesn't return. */ run_guest(); } -- cgit v1.1 From 5230ff0cccb0611830bb02b097535868df02752a Mon Sep 17 00:00:00 2001 From: Philip Sanderson Date: Thu, 20 Jan 2011 21:37:28 -0600 Subject: lguest: example launcher to use guard pages, drop PROT_EXEC, fix limit logic PROT_EXEC seems to be completely unnecessary (as the lguest binary never executes there), and will allow it to work with SELinux (and more importantly, PaX :-) as they can/do forbid writable and executable mappings. Also, map PROT_NONE guard pages at start and end of guest memory for extra paranoia. I changed the length check to addr + size > guest_limit because >= is wrong (addr of 0, size of getpagesize() with a guest_limit of getpagesize() would false positive). Signed-off-by: Rusty Russell --- Documentation/lguest/lguest.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index f64b85b..d9da7e1 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -301,20 +301,27 @@ static void *map_zeroed_pages(unsigned int num) /* * We use a private mapping (ie. if we write to the page, it will be - * copied). + * copied). We allocate an extra two pages PROT_NONE to act as guard + * pages against read/write attempts that exceed allocated space. */ - addr = mmap(NULL, getpagesize() * num, - PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0); + addr = mmap(NULL, getpagesize() * (num+2), + PROT_NONE, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) err(1, "Mmapping %u pages of /dev/zero", num); + if (mprotect(addr + getpagesize(), getpagesize() * num, + PROT_READ|PROT_WRITE) == -1) + err(1, "mprotect rw %u pages failed", num); + /* * One neat mmap feature is that you can close the fd, and it * stays mapped. */ close(fd); - return addr; + /* Return address after PROT_NONE page */ + return addr + getpagesize(); } /* Get some more pages for a device. */ @@ -346,7 +353,7 @@ static void map_at(int fd, void *addr, unsigned long offset, unsigned long len) * done to it. This allows us to share untouched memory between * Guests. */ - if (mmap(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC, + if (mmap(addr, len, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED) return; @@ -576,10 +583,10 @@ static void *_check_pointer(unsigned long addr, unsigned int size, unsigned int line) { /* - * We have to separately check addr and addr+size, because size could - * be huge and addr + size might wrap around. + * Check if the requested address and size exceeds the allocated memory, + * or addr + size wraps around. */ - if (addr >= guest_limit || addr + size >= guest_limit) + if ((addr + size) > guest_limit || (addr + size) < addr) errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr); /* * We return a pointer for the caller's convenience, now we know it's -- cgit v1.1 From 85c0647275b60380e19542d43420184e86418d86 Mon Sep 17 00:00:00 2001 From: Philip Sanderson Date: Thu, 20 Jan 2011 21:37:29 -0600 Subject: lguest: document --rng in example Launcher Rusty Russell wrote: > Ah, it will appear as /dev/hwrng. It's a weirdness of Linux that our actual > hardware number generators are not wired up to /dev/random... Reflected this in the documentation, thanks :-) Signed-off-by: Rusty Russell --- Documentation/lguest/lguest.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt index 6ccaf8e..dad9997 100644 --- a/Documentation/lguest/lguest.txt +++ b/Documentation/lguest/lguest.txt @@ -117,6 +117,11 @@ Running Lguest: for general information on how to get bridging to work. +- Random number generation. Using the --rng option will provide a + /dev/hwrng in the guest that will read from the host's /dev/random. + Use this option in conjunction with rng-tools (see ../hw_random.txt) + to provide entropy to the guest kernel's /dev/random. + There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest Good luck! -- cgit v1.1