File xsa443-11.patch of Package xen.33138
From 273cc7ecf0a66334f24f6f740bcd441b542b3323 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Thu, 28 Sep 2023 12:22:35 +0200
Subject: [PATCH 11/11] libxl: limit bootloader execution in restricted mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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 | 8 ++++++
tools/libxl/libxl_bootloader.c | 40 +++++++++++++++++++++++++++++
tools/libxl/libxl_internal.h | 2 ++
3 files changed, 50 insertions(+)
--- a/docs/man/xl.1.pod.in
+++ b/docs/man/xl.1.pod.in
@@ -1983,6 +1983,14 @@ NOTE: Each domain MUST have a SEPARATE u
See docs/features/qemu-deprivilege.pandoc for more information.
+=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
--- a/tools/libxl/libxl_bootloader.c
+++ b/tools/libxl/libxl_bootloader.c
@@ -34,6 +34,8 @@ static void bootloader_keystrokes_copyfa
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,
@@ -301,6 +303,7 @@ void libxl__bootloader_init(libxl__bootl
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);
@@ -318,6 +321,7 @@ static void bootloader_cleanup(libxl__eg
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);
@@ -379,6 +383,7 @@ static void bootloader_stop(libxl__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]",
@@ -641,6 +646,25 @@ static void bootloader_gotptys(libxl__eg
struct termios termattr;
+ if (getenv("LIBXL_BOOTLOADER_RESTRICT") ||
+ getenv("LIBXL_BOOTLOADER_USER")) {
+ 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) {
rc = ERROR_FAIL;
@@ -706,6 +730,21 @@ static void bootloader_display_copyfail(
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,
@@ -722,6 +761,7 @@ static void bootloader_finished(libxl__e
STATE_AO_GC(bl->ao);
int rc;
+ libxl__ev_time_deregister(gc, &bl->time);
libxl__datacopier_kill(&bl->keystrokes);
libxl__datacopier_kill(&bl->display);
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -103,6 +103,7 @@
#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
@@ -3682,6 +3683,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;