=back
+=head1 ENVIRONMENT VARIABLES
+
+The following environment variables shall affect the execution of xl:
+
+=over 4
+
+=item LIBXL_BOOTLOADER_RESTRICT
+
+Equivalent to L<xl.cfg(5)> B<bootloader_restrict> option. Provided for
+compatibility reasons. Having this variable set is equivalent to enabling
+the option, even if the value is 0.
+
+If set takes precedence over L<xl.cfg(5)> and L<xl.conf(5)>
+B<bootloader_restrict> options.
+
+=item LIBXL_BOOTLOADER_USER
+
+Equivalent to L<xl.cfg(5)> B<bootloader_user> option. Provided for
+compatibility reasons.
+
+If set takes precedence over L<xl.cfg(5)> B<bootloader_user> option.
+
+=back
+
=head1 SEE ALSO
The following man pages:
program. Alternatively if the argument is a simple string then it will
be split into words at whitespace B<(this second option is deprecated)>.
+=item B<bootloader_restrict=BOOLEAN>
+
+Attempt to restrict the bootloader after startup, to limit the
+consequences of security vulnerabilities due to parsing guest
+owned image files.
+
+See docs/features/qemu-deprivilege.pandoc for more information
+on how to setup the unprivileged users.
+
+Note that running the bootloader in restricted mode also implies using
+non-interactive mode, and the disk image must be readable by the
+restricted user.
+
+=item B<bootloader_user=USERNAME>
+
+When using bootloader_restrict, run the bootloader as this user. If not
+set the default QEMU restrict users will be used.
+
+NOTE: Each domain MUST have a SEPARATE username.
+
+See docs/features/qemu-deprivilege.pandoc for more information.
+
=item B<e820_host=BOOLEAN>
Selects whether to expose the host e820 (memory map) to the guest via
program. Alternatively if the argument is a simple string then it will
be split into words at whitespace B<(this second option is deprecated)>.
+=item B<bootloader_restrict=BOOLEAN>
+
+Attempt to restrict the bootloader after startup, to limit the
+consequences of security vulnerabilities due to parsing guest
+owned image files.
+
+See docs/features/qemu-deprivilege.pandoc for more information
+on how to setup the unprivileged users.
+
+Note that running the bootloader in restricted mode also implies using
+non-interactive mode, and the disk image must be readable by the
+restricted user.
+
+=item B<bootloader_user=USERNAME>
+
+When using bootloader_restrict, run the bootloader as this user.
+
+NOTE: Each domain MUST have a SEPARATE username.
+
+See docs/features/qemu-deprivilege.pandoc for more information.
+
=item B<timer_mode="MODE">
Specifies the mode for Virtual Timers. The valid values are as follows:
concerning CPU affinity. One example is CPU pools. Users should always double
check that the required affinity has taken effect.
+=item B<bootloader_restrict=BOOLEAN>
+
+System wide default for whether the bootloader should be run in a restricted
+environment. See L<xl.cfg(5)> B<bootloader_restrict> for more information on
+how to setup and use the option.
+
=back
=head1 SEE ALSO
* first ABI incompatible change in a development branch.
*/
+#define LIBXL_HAVE_BOOTLOADER_RESTRICT 1
+/*
+ * LIBXL_HAVE_BOOTLOADER_RESTRICT indicates the presence of the
+ * bootloader_restrict and bootloader_user fields in libxl_domain_build_info.
+ * Such fields signal the need to pass a --runas parameter to the bootloader
+ * executable in order to not run it as the same user as libxl.
+ */
+
/*
* libxl memory management
*
#include "libxl_osdeps.h" /* must come before any other headers */
+#include <pwd.h>
#include <termios.h>
#ifdef HAVE_UTMP_H
#include <utmp.h>
bl->args[bl->nargs++] = arg;
}
-static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
- const char *bootloader_path)
+static int bootloader_uid(libxl__gc *gc, domid_t guest_domid,
+ const char *user, uid_t *intended_uid)
+{
+ struct passwd *user_base, user_pwbuf;
+ int rc;
+
+ if (user) {
+ rc = userlookup_helper_getpwnam(gc, user, &user_pwbuf, &user_base);
+ if (rc) return rc;
+
+ if (!user_base) {
+ LOGD(ERROR, guest_domid, "Couldn't find user %s", user);
+ return ERROR_INVAL;
+ }
+
+ *intended_uid = user_base->pw_uid;
+ return 0;
+ }
+
+ /* Re-use QEMU user range for the bootloader. */
+ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_RANGE_BASE,
+ &user_pwbuf, &user_base);
+ if (rc) return rc;
+
+ if (user_base) {
+ struct passwd *user_clash, user_clash_pwbuf;
+ uid_t temp_uid = user_base->pw_uid + guest_domid;
+
+ rc = userlookup_helper_getpwuid(gc, temp_uid, &user_clash_pwbuf,
+ &user_clash);
+ if (rc) return rc;
+
+ if (user_clash) {
+ LOGD(ERROR, guest_domid,
+ "wanted to use uid %ld (%s + %d) but that is user %s !",
+ (long)temp_uid, LIBXL_QEMU_USER_RANGE_BASE,
+ guest_domid, user_clash->pw_name);
+ return ERROR_INVAL;
+ }
+
+ *intended_uid = temp_uid;
+ return 0;
+ }
+
+ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_SHARED, &user_pwbuf,
+ &user_base);
+ if (rc) return rc;
+
+ if (user_base) {
+ LOGD(WARN, guest_domid, "Could not find user %s, falling back to %s",
+ LIBXL_QEMU_USER_RANGE_BASE, LIBXL_QEMU_USER_SHARED);
+ *intended_uid = user_base->pw_uid;
+
+ return 0;
+ }
+
+ LOGD(ERROR, guest_domid,
+ "Could not find user %s or range base pseudo-user %s, cannot restrict",
+ LIBXL_QEMU_USER_SHARED, LIBXL_QEMU_USER_RANGE_BASE);
+
+ return ERROR_INVAL;
+}
+
+static int make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
+ const char *bootloader_path)
{
const libxl_domain_build_info *info = bl->info;
ARG(GCSPRINTF("--ramdisk=%s", info->ramdisk));
if (info->cmdline && *info->cmdline != '\0')
ARG(GCSPRINTF("--args=%s", info->cmdline));
+ if (libxl_defbool_val(info->bootloader_restrict)) {
+ uid_t uid = -1;
+ int rc = bootloader_uid(gc, bl->domid, info->bootloader_user,
+ &uid);
+
+ if (rc) return rc;
+
+ assert(uid != -1);
+ if (!uid) {
+ LOGD(ERROR, bl->domid, "bootloader restrict UID is 0 (root)!");
+ return ERROR_INVAL;
+ }
+ LOGD(DEBUG, bl->domid, "using uid %ld", (long)uid);
+ ARG(GCSPRINTF("--runas=%ld", (long)uid));
+ ARG("--quiet");
+ }
ARG(GCSPRINTF("--output=%s", bl->outputpath));
ARG("--output-format=simple0");
/* Sentinel for execv */
ARG(NULL);
+ return 0;
#undef ARG
}
bootloader = bltmp;
}
- make_bootloader_args(gc, bl, bootloader);
+ rc = make_bootloader_args(gc, bl, bootloader);
+ if (rc) goto out;
bl->openpty.ao = ao;
bl->openpty.callback = bootloader_gotptys;
return -ERROR_INVAL;
}
+ /* Assume that providing a bootloader user implies enabling restrict. */
+ libxl_defbool_setdefault(&b_info->bootloader_restrict,
+ !!b_info->bootloader_user);
+ /* ENV takes precedence over provided domain_build_info. */
+ if (getenv("LIBXL_BOOTLOADER_RESTRICT") ||
+ getenv("LIBXL_BOOTLOADER_USER"))
+ libxl_defbool_set(&b_info->bootloader_restrict, true);
+ if(getenv("LIBXL_BOOTLOADER_USER"))
+ b_info->bootloader_user =
+ libxl__strdup(gc, getenv("LIBXL_BOOTLOADER_USER"));
+
return 0;
}
* On error, return a libxl-style error code.
*/
#define DEFINE_USERLOOKUP_HELPER(NAME,SPEC_TYPE,STRUCTNAME,SYSCONF) \
- static int userlookup_helper_##NAME(libxl__gc *gc, \
- SPEC_TYPE spec, \
- struct STRUCTNAME *resultbuf, \
- struct STRUCTNAME **out) \
+ int userlookup_helper_##NAME(libxl__gc *gc, \
+ SPEC_TYPE spec, \
+ struct STRUCTNAME *resultbuf, \
+ struct STRUCTNAME **out) \
{ \
struct STRUCTNAME *resultp = NULL; \
char *buf = NULL; \
struct xc_msr *msr;
};
+struct passwd;
+_hidden int userlookup_helper_getpwnam(libxl__gc*, const char *user,
+ struct passwd *res,
+ struct passwd **out);
+_hidden int userlookup_helper_getpwuid(libxl__gc*, uid_t uid,
+ struct passwd *res,
+ struct passwd **out);
+
#endif
/*
("acpi", libxl_defbool),
("bootloader", string),
("bootloader_args", libxl_string_list),
+ ("bootloader_restrict", libxl_defbool),
+ ("bootloader_user", string),
("timer_mode", libxl_timer_mode),
("nested_hvm", libxl_defbool),
("apic", libxl_defbool),
int max_maptrack_frames = -1;
int max_grant_version = LIBXL_MAX_GRANT_DEFAULT;
libxl_domid domid_policy = INVALID_DOMID;
+libxl_defbool bootloader_restrict;
xentoollog_level minmsglevel = minmsglevel_default;
fprintf(stderr, "invalid domid_policy option");
}
+ xlu_cfg_get_defbool(config, "bootloader_restrict",
+ &bootloader_restrict, 0);
+
xlu_cfg_destroy(config);
}
extern libxl_bitmap global_hvm_affinity_mask;
extern libxl_bitmap global_pv_affinity_mask;
extern libxl_domid domid_policy;
+extern libxl_defbool bootloader_restrict;
enum output_format {
OUTPUT_FORMAT_JSON,
exit(-ERROR_FAIL);
}
#endif
+ xlu_cfg_get_defbool(config, "bootloader_restrict",
+ &b_info->bootloader_restrict, 0);
+ if (!libxl_defbool_is_default(bootloader_restrict))
+ libxl_defbool_setdefault(&b_info->bootloader_restrict,
+ libxl_defbool_val(bootloader_restrict));
+ xlu_cfg_replace_string(config, "bootloader_user",
+ &b_info->bootloader_user, 0);
switch (xlu_cfg_get_list_as_string_list(config, "bootloader_args",
&b_info->bootloader_args, 1)) {