]> xenbits.xensource.com Git - people/royger/xen.git/commitdiff
libxl: limit bootloader execution in restricted mode
authorRoger Pau Monne <roger.pau@citrix.com>
Thu, 28 Sep 2023 10:22:35 +0000 (12:22 +0200)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 11 Oct 2023 05:36:50 +0000 (06:36 +0100)
Introduce a timeout for bootloader execution when running in restricted mode.

Allow overwriting the default time out with an environment provided value.

This is part of XSA-443 / CVE-2023-34325

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
docs/man/xl.1.pod.in
tools/libs/light/libxl_bootloader.c
tools/libs/light/libxl_internal.h

index 73e2b3b6114c99d633f0f27de0ef2391517e8a7c..bed8393473c9673498b7b5d4a15297e7d263251d 100644 (file)
@@ -1985,6 +1985,14 @@ compatibility reasons.
 
 If set takes precedence over L<xl.cfg(5)> B<bootloader_user> option.
 
+=item LIBXL_BOOTLOADER_TIMEOUT
+
+Timeout in seconds for bootloader execution when running in restricted mode.
+Otherwise the build time default in LIBXL_BOOTLOADER_TIMEOUT will be used.
+
+If defined the value must be an unsigned integer between 0 and INT_MAX,
+otherwise behavior is undefined.  Setting to 0 disables the timeout.
+
 =back
 
 =head1 SEE ALSO
index d732367fc0535a0a48efba7461f42f3a27ac7b33..279a9cdf91f6c16ab12f19f7034dc19fb6e765d4 100644 (file)
@@ -30,6 +30,8 @@ static void bootloader_keystrokes_copyfail(libxl__egc *egc,
        libxl__datacopier_state *dc, int rc, int onwrite, int errnoval);
 static void bootloader_display_copyfail(libxl__egc *egc,
        libxl__datacopier_state *dc, int rc, int onwrite, int errnoval);
+static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                               const struct timeval *requested_abs, int rc);
 static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc,
                                    int rc);
 static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
@@ -296,6 +298,7 @@ void libxl__bootloader_init(libxl__bootloader_state *bl)
     bl->ptys[0].master = bl->ptys[0].slave = 0;
     bl->ptys[1].master = bl->ptys[1].slave = 0;
     libxl__ev_child_init(&bl->child);
+    libxl__ev_time_init(&bl->time);
     libxl__domaindeathcheck_init(&bl->deathcheck);
     bl->keystrokes.ao = bl->ao;  libxl__datacopier_init(&bl->keystrokes);
     bl->display.ao = bl->ao;     libxl__datacopier_init(&bl->display);
@@ -313,6 +316,7 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl)
     libxl__domaindeathcheck_stop(gc,&bl->deathcheck);
     libxl__datacopier_kill(&bl->keystrokes);
     libxl__datacopier_kill(&bl->display);
+    libxl__ev_time_deregister(gc, &bl->time);
     for (i=0; i<2; i++) {
         libxl__carefd_close(bl->ptys[i].master);
         libxl__carefd_close(bl->ptys[i].slave);
@@ -374,6 +378,7 @@ static void bootloader_stop(libxl__egc *egc,
 
     libxl__datacopier_kill(&bl->keystrokes);
     libxl__datacopier_kill(&bl->display);
+    libxl__ev_time_deregister(gc, &bl->time);
     if (libxl__ev_child_inuse(&bl->child)) {
         r = kill(bl->child.pid, SIGTERM);
         if (r) LOGED(WARN, bl->domid, "%sfailed to kill bootloader [%lu]",
@@ -635,6 +640,25 @@ static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
         LOGD(DEBUG, bl->domid, "  bootloader arg: %s", *blarg);
 
     struct termios termattr;
+    const libxl_domain_build_info *info = bl->info;
+
+    if (libxl_defbool_val(info->bootloader_restrict)) {
+        const char *timeout_env = getenv("LIBXL_BOOTLOADER_TIMEOUT");
+        int timeout = timeout_env ? atoi(timeout_env)
+                                  : LIBXL_BOOTLOADER_TIMEOUT;
+
+        if (timeout) {
+            /* Set execution timeout */
+            rc = libxl__ev_time_register_rel(ao, &bl->time,
+                                            bootloader_timeout,
+                                            timeout * 1000);
+            if (rc) {
+                LOGED(ERROR, bl->domid,
+                      "unable to register timeout for bootloader execution");
+                goto out;
+            }
+        }
+    }
 
     pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished);
     if (pid == -1) {
@@ -701,6 +725,21 @@ static void bootloader_display_copyfail(libxl__egc *egc,
     libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, display);
     bootloader_copyfail(egc, "bootloader output", bl, 1, rc,onwrite,errnoval);
 }
+static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                               const struct timeval *requested_abs, int rc)
+{
+    libxl__bootloader_state *bl = CONTAINER_OF(ev, *bl, time);
+    STATE_AO_GC(bl->ao);
+
+    libxl__ev_time_deregister(gc, &bl->time);
+
+    assert(libxl__ev_child_inuse(&bl->child));
+    LOGD(ERROR, bl->domid, "killing bootloader because of timeout");
+
+    libxl__ev_child_kill_deregister(ao, &bl->child, SIGKILL);
+
+    bootloader_callback(egc, bl, rc);
+}
 
 static void bootloader_domaindeath(libxl__egc *egc,
                                    libxl__domaindeathcheck *dc,
@@ -717,6 +756,7 @@ static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
     STATE_AO_GC(bl->ao);
     int rc;
 
+    libxl__ev_time_deregister(gc, &bl->time);
     libxl__datacopier_kill(&bl->keystrokes);
     libxl__datacopier_kill(&bl->display);
 
index 1219ff8dbd899dc4d333e136d781ab5645b479fd..d5732d1c37920bb34b0883c1cef2c4f9ffaf6838 100644 (file)
 #define LIBXL_QMP_CMD_TIMEOUT 10
 #define LIBXL_STUBDOM_START_TIMEOUT 30
 #define LIBXL_QEMU_BODGE_TIMEOUT 2
+#define LIBXL_BOOTLOADER_TIMEOUT 120
 #define LIBXL_XENCONSOLE_LIMIT 1048576
 #define LIBXL_XENCONSOLE_PROTOCOL "vt100"
 #define LIBXL_MAXMEM_CONSTANT 1024
@@ -3744,6 +3745,7 @@ struct libxl__bootloader_state {
     libxl__openpty_state openpty;
     libxl__openpty_result ptys[2];  /* [0] is for bootloader */
     libxl__ev_child child;
+    libxl__ev_time time;
     libxl__domaindeathcheck deathcheck;
     int nargs, argsspace;
     const char **args;