[Lguest] NX bit support

Philip Sanderson philip.k.sanderson at gmail.com
Mon Nov 8 22:22:20 EST 2010


On Mon, Nov 8, 2010 at 8:27 PM, Rusty Russell <rusty at rustcorp.com.au> wrote:

> On Sat, 6 Nov 2010 10:43:26 pm Philip Sanderson wrote:
> > Hello,
> >
> > short version:
> >
> > - Any plans for NX bit support?
>
> I haven't even looked at it.  I NX requires PAE, but that's all I know...
>
>
Hmm. Well, it sets an extra bit in the PTE entry, which I think is being
filtered out somewhere.


> Oh, and it's generally preferred in the kernel world to put patches
> inline for easier quoting BTW.


> > - Patch for Documentation/lguest/lguest.c -- remove prot_exec, adds
> chroot.
>
> Hmm, it's an lguest flaw that we don't enforce this in the module, really.
> But making life easier for PaX/SELinux makes sense.



could you re-send with that fixed?
>
>
As requested. I have updated lguest.txt to reflect that rng-tools is
required.

diff -ur linux-2.6.35.8-orig/Documentation/lguest/lguest.c
linux-2.6.35.8/Documentation/lguest/lguest.c
--- linux-2.6.35.8-orig/Documentation/lguest/lguest.c    2010-10-29
15:52:43.000000000 +1100
+++ linux-2.6.35.8/Documentation/lguest/lguest.c    2010-11-08
21:51:34.244586003 +1100
@@ -39,6 +39,9 @@
 #include <limits.h>
 #include <stddef.h>
 #include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+
 #include "linux/lguest_launcher.h"
 #include "linux/virtio_config.h"
 #include "linux/virtio_net.h"
@@ -298,20 +301,25 @@

     /*
      * 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 invalid 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 addr+getpagesize();
 }

 /* Get some more pages for a device. */
@@ -343,7 +351,7 @@
      * 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;

@@ -573,11 +581,13 @@
                 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
      * safe to use.
@@ -1882,6 +1892,8 @@
     { "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)
@@ -1904,6 +1916,12 @@
     /* 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;

@@ -1960,6 +1978,16 @@
         case 'i':
             initrd_name = optarg;
             break;
+        case 'u':
+            user_details = getpwnam(optarg);
+
+            if(! user_details)
+                err(1, "getpwnam failed, incorrect uername?");
+
+            break;
+        case 'c':
+            chroot_path = optarg;
+            break;
         default:
             warnx("Unknown argument %s", argv[optind]);
             usage();
@@ -2031,6 +2059,39 @@
     /* 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");
+    }
+
+    /* 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");
+    }
+
+
     /* Finally, run the Guest.  This doesn't return. */
     run_guest();
 }
diff -ur linux-2.6.35.8-orig/Documentation/lguest/lguest.txt
linux-2.6.35.8/Documentation/lguest/lguest.txt
--- linux-2.6.35.8-orig/Documentation/lguest/lguest.txt    2010-10-29
15:52:43.000000000 +1100
+++ linux-2.6.35.8/Documentation/lguest/lguest.txt    2010-11-08
21:29:19.188586003 +1100
@@ -114,6 +114,11 @@
   See http://linux-net.osdl.org/index.php/Bridge for general information
   on how to get bridging working.

+- 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!


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

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 :-)


> Thanks!
> Rusty.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/lguest/attachments/20101108/935ec7c0/attachment-0001.html>


More information about the Lguest mailing list