# Commit dbdcd69e6452c277d1456b03445cbd7778194909
# Date 2017-10-11 12:51:22 +0100
# Author Ian Jackson <ian.jackson@eu.citrix.com>
# Committer Ian Jackson <Ian.Jackson@eu.citrix.com>
libxl: dm_restrict: Support uid range user

Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>

Backport: docs/man/xl.cfg.pod.5.in change dropped, as the part of the doc
          it would extend does not exist, and introducing that wouldn't be
          appropriate (it discusses dm_restrict, which is added only in a
          later Xen version)

--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -23,6 +23,7 @@
 #include <xen/hvm/e820.h>
 #include <sys/types.h>
 #include <pwd.h>
+#include <grp.h>
 
 static const char *libxl_tapif_script(libxl__gc *gc)
 {
@@ -733,6 +734,9 @@ libxl__detect_gfx_passthru_kind(libxl__g
  *  userlookup_helper_getpwnam(libxl__gc*, const char *user,
  *                             struct passwd **pwd_r);
  *
+ *  userlookup_helper_getpwuid(libxl__gc*, uid_t uid,
+ *                             struct passwd **pwd_r);
+ *
  *  returns 1 if the user was found, 0 if it was not, -1 on error
  */
 #define DEFINE_USERLOOKUP_HELPER(NAME,SPEC_TYPE,STRUCTNAME,SYSCONF)     \
@@ -772,6 +776,7 @@ libxl__detect_gfx_passthru_kind(libxl__g
     }
 
 DEFINE_USERLOOKUP_HELPER(getpwnam, const char*, passwd, _SC_GETPW_R_SIZE_MAX);
+DEFINE_USERLOOKUP_HELPER(getpwuid, uid_t,       passwd, _SC_GETPW_R_SIZE_MAX);
 
 /* colo mode */
 enum {
@@ -936,7 +941,7 @@ static int libxl__build_device_model_arg
     uint64_t ram_size;
     const char *path, *chardev;
     char *user = NULL;
-    struct passwd user_pwbuf;
+    struct passwd *user_base, user_pwbuf;
 
     dm_args = flexarray_make(gc, 16, 1);
     dm_envs = flexarray_make(gc, 16, 1);
@@ -1637,6 +1642,33 @@ static int libxl__build_device_model_arg
         if (ret > 0)
             goto end_search;
 
+        ret = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_RANGE_BASE,
+                                         &user_pwbuf, &user_base);
+        if (ret < 0)
+            return ret;
+        if (ret > 0) {
+            struct passwd *user_clash, user_clash_pwbuf;
+            uid_t intended_uid = user_base->pw_uid + guest_domid;
+            ret = userlookup_helper_getpwuid(gc, intended_uid,
+                                             &user_clash_pwbuf, &user_clash);
+            if (ret < 0)
+                return ret;
+            if (ret > 0) {
+                LOGD(ERROR, guest_domid,
+                     "wanted to use uid %ld (%s + %d) but that is user %s !",
+                     (long)intended_uid, LIBXL_QEMU_USER_RANGE_BASE,
+                     guest_domid, user_clash->pw_name);
+                return ERROR_FAIL;
+            }
+            LOGD(DEBUG, guest_domid, "using uid %ld", (long)intended_uid);
+            flexarray_append(dm_args, "-runas");
+            flexarray_append(dm_args,
+                             GCSPRINTF("%ld:%ld", (long)intended_uid,
+                                       (long)user_base->pw_gid));
+            user = NULL; /* we have taken care of it */
+            goto end_search;
+        }
+
         user = LIBXL_QEMU_USER_SHARED;
         ret = userlookup_helper_getpwnam(gc, user, &user_pwbuf, 0);
         if (ret < 0)
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -4345,6 +4345,7 @@ _hidden int libxl__read_sysfs_file_conte
 #define LIBXL_QEMU_USER_PREFIX "xen-qemuuser"
 #define LIBXL_QEMU_USER_BASE   LIBXL_QEMU_USER_PREFIX"-domid"
 #define LIBXL_QEMU_USER_SHARED LIBXL_QEMU_USER_PREFIX"-shared"
+#define LIBXL_QEMU_USER_RANGE_BASE LIBXL_QEMU_USER_PREFIX"-range-base"
 
 static inline bool libxl__acpi_defbool_val(const libxl_domain_build_info *b_info)
 {
