From 1a4412f56894b6a514ddca19d478fb157d867315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Tomko?= Date: Wed, 13 Dec 2023 14:05:32 +0100 Subject: [PATCH] qemu: virtiofs: auto-fill idmap for unprivileged use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user did not specify any uid mapping, map its own user ID to ID 0 inside the container and the rest of the IDs to the first found user's authorized range in /etc/sub[ug]id https://issues.redhat.com/browse/RHEL-7386 https://gitlab.com/libvirt/libvirt/-/issues/535 Signed-off-by: Ján Tomko Reviewed-by: Michal Privoznik --- src/qemu/qemu_virtiofs.c | 76 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_virtiofs.c b/src/qemu/qemu_virtiofs.c index 4dacd37a1c..d539d0a192 100644 --- a/src/qemu/qemu_virtiofs.c +++ b/src/qemu/qemu_virtiofs.c @@ -369,12 +369,84 @@ qemuVirtioFSSetupCgroup(virDomainObj *vm, return 0; } +static int +qemuVirtioFSPrepareIdMap(virDomainFSDef *fs) +{ + g_autofree char *username = NULL; + g_autofree char *groupname = NULL; + virSubID *subuids = NULL; + virSubID *subgids = NULL; + uid_t euid = geteuid(); + uid_t egid = getegid(); + int subuidlen = 0; + int subgidlen = 0; + size_t i; + + username = virGetUserName(euid); + groupname = virGetGroupName(egid); + + fs->idmap.uidmap = g_new0(virDomainIdMapEntry, 2); + fs->idmap.gidmap = g_new0(virDomainIdMapEntry, 2); + + if ((subuidlen = virGetSubIDs(&subuids, "/etc/subuid")) < 0) + return -1; + + fs->idmap.uidmap[0].start = 0; + fs->idmap.uidmap[0].target = euid; + fs->idmap.uidmap[0].count = 1; + fs->idmap.nuidmap = 1; + + for (i = 0; i < subuidlen; i++) { + if ((subuids[i].idstr && STREQ(subuids[i].idstr, username)) || + subuids[i].id == euid) { + fs->idmap.uidmap[1].start = 1; + fs->idmap.uidmap[1].target = subuids[i].start; + fs->idmap.uidmap[1].count = subuids[i].range; + fs->idmap.nuidmap++; + break; + } + } + + virSubIDsFree(&subuids, subuidlen); + + if ((subgidlen = virGetSubIDs(&subgids, "/etc/subgid")) < 0) + return -1; + + fs->idmap.gidmap[0].start = 0; + fs->idmap.gidmap[0].target = getegid(); + fs->idmap.gidmap[0].count = 1; + fs->idmap.ngidmap = 1; + + for (i = 0; i < subgidlen; i++) { + if ((subgids[i].idstr && STREQ(subgids[i].idstr, groupname)) || + subgids[i].id == egid) { + fs->idmap.gidmap[1].start = 1; + fs->idmap.gidmap[1].target = subgids[i].start; + fs->idmap.gidmap[1].count = subgids[i].range; + fs->idmap.ngidmap++; + break; + } + } + + virSubIDsFree(&subgids, subgidlen); + + return 0; +} + int qemuVirtioFSPrepareDomain(virQEMUDriver *driver, virDomainFSDef *fs) { - if (fs->binary || fs->sock) + if (fs->sock) return 0; - return qemuVhostUserFillDomainFS(driver, fs); + if (!fs->binary && qemuVhostUserFillDomainFS(driver, fs) < 0) + return -1; + + if (!driver->privileged && !fs->idmap.uidmap) { + if (qemuVirtioFSPrepareIdMap(fs) < 0) + return -1; + } + + return 0; }