From nobody Fri Dec 19 19:02:50 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 173977652207749.75340691130907; Sun, 16 Feb 2025 23:15:22 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id 747491CEF; Mon, 17 Feb 2025 02:15:20 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id DA1AA1CA0; Mon, 17 Feb 2025 02:14:57 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id C10371C5C; Mon, 17 Feb 2025 02:14:54 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 2970215BF for ; Mon, 17 Feb 2025 02:14:54 -0500 (EST) Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-251-YbbCFlH6MCe80Ryvq5TErQ-1; Mon, 17 Feb 2025 02:14:52 -0500 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4EA28180034E for ; Mon, 17 Feb 2025 07:14:51 +0000 (UTC) Received: from vhost3.router.laine.org (unknown [10.22.88.96]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B51AE19560A3; Mon, 17 Feb 2025 07:14:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739776493; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=/k4WGRadiBIYyxv4M/qsf01R0GjVKTXPHwPVO/1cdSo=; b=NZS6i+UXtvbSFTVcsGPbqBXl7RrKkTWXoK7DgQzaqkltyq0h/4DBCsERbycOw99He2cYxZ ckpn0UIoDI/7tbx+taheI28/EMyHgPUlj9ySqMk2ogsp8ki/VVyQTOZFCAMh+TM1n0cu5V cCDmuGEathn9loSBFt5ryQN+p8vCB58= X-MC-Unique: YbbCFlH6MCe80Ryvq5TErQ-1 X-Mimecast-MFC-AGG-ID: YbbCFlH6MCe80Ryvq5TErQ_1739776491 From: Laine Stump To: devel@lists.libvirt.org Cc: Rich Jones Subject: [PATCH RFC] util: pick a better runtime directory when XDG_RUNTIME_DIR isn't set Date: Mon, 17 Feb 2025 02:14:49 -0500 Message-ID: <20250217071449.1443346-1-laine@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 5g9VayDEza1WuXKSPPId6RteDVpzm5F22B1CtLwRc5E_1739776491 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: F2FGTGGWHC2DMDK65U6F5HVD743UWPG5 X-Message-ID-Hash: F2FGTGGWHC2DMDK65U6F5HVD743UWPG5 X-MailFrom: laine@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1739776525523019100 Content-Type: text/plain; charset="utf-8"; x-default="true" =3D=3D=3D=3D=3D=3D I'm sending this as an RFC just because what it's doing feels kind of dirty - directly examining XDG_RUNTIME_DIR seems like an "end run" around the Glib API. If anyone has a better idea of what to do, please give details :-) =3D=3D=3D=3D=3D=3D When running unprivileged (i.e. not as root, but as a regular user), libvirt calls g_get_user_runtime_dir() (from Glib) to get the name of a directory where status files can be saved. This is a directory that is 1) writeable by the current user, and 2) will remain there until the host reboots, but then 3) be erased after the reboot. This is used for pidfiles, sockets created to communicate between processes, status XML of active domains, etc. Normally g_get_user_runtime_dir() returns the setting of XDG_RUNTIME_DIR in the user's environment; usually this is set to /run/user/${UID} (e.g. /run/user/1000) - that directory is created when a user first logs in and is owned by the user, but is cleared out when the system reboots (more specifically, this directory usually resides in a tmpfs, and so disappears when that tmpfs is unmounted). But sometimes XDG_RUNTIME_DIR isn't set in the user's environment. In that case, g_get_user_runtime_dir() returns ${HOME}/.config (e.g. /home/laine/.config). This directory fulfills the first 2 criteria above, but fails the 3rd. This isn't just some pedantic complaint - libvirt actually depends on the directory being cleared out during a reboot - otherwise it might think that stale status files are indicating active guests when in fact the guests were shutdown during the reboot). In my opinion this behavior is a bug in Glib - see the requirements for XDG_RUNTIME in the FreeDesktop documentation here: https://specifications.freedesktop.org/basedir-spec/latest/#variables but they've documented the behavior as proper in the Glib docs for g_get_user_runtime_dir(), and so likely will consider it not a bug. Beyond that, aside from failing the "must be cleared out during a reboot" requirement, use of $HOME/.cache in this way also disturbs SELinux, which gives an AVC denial when libvirt (or passt) tries to create a file or socket in that directory (the SELinux policy permits use of /run/user/$UID, but not of $HOME/.config). We *could* add that to the SELinux policy, but since the glib behavior doesn't All of the above is a very long leadup to the functionality in this patch: rather than blindly accepting the path returned from g_get_user_runtime_dir(), we first check if XDG_RUNTIME_DIR is set; if it isn't set then we look to see if /run/user/$UID exists and is writable by this user, if so we use *that* as the directory for our status files. Otherwise (both when XDG_RUNTIME_DIR is set, and when /run/user/$UID isn't usable) we fallback to just using the path returned by g_get_user_runtime_dir() - that isn't perfect, but it's what we were doing before, so at least it's not any worse. Resolves: https://issues.redhat.com/browse/RHEL-70222 Signed-off-by: Laine Stump --- src/util/virutil.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/util/virutil.c b/src/util/virutil.c index 2abcb282fe..4c7f4b62bc 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -538,6 +538,28 @@ char *virGetUserRuntimeDirectory(void) #ifdef WIN32 return g_strdup(g_get_user_runtime_dir()); #else + /* tl;dr - if XDG_RUNTIME_DIR is set, use g_get_user_runtime_dir(). + * if not set, then see if /run/user/$UID works + * if so, use that, else fallback to g_get_user_runtime_dir() + * + * this is done because the directory returned by + * g_get_user_runtime_dir() when XDG_RUNTIME_DIR isn't set is + * "suboptimal" (it's a location that is owned by the user, but + * isn't erased when the user completely logs out) + */ + + if (!getenv("XDG_RUNTIME_DIR")) { + g_autofree char *runtime_dir =3D NULL; + struct stat sb; + + runtime_dir =3D g_strdup_printf("/run/user/%d", getuid()); + if (virFileIsDir(runtime_dir) && + (stat(runtime_dir, &sb) =3D=3D 0) && (sb.st_mode & S_IWUSR)) { + return g_build_filename(runtime_dir, "libvirt", NULL); + } + } + + /* either XDG_RUNTIME_DIR was set, or /run/usr/$UID wasn't writable */ return g_build_filename(g_get_user_runtime_dir(), "libvirt", NULL); #endif } --=20 2.47.1