From nobody Tue Feb 10 18:21:32 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1687376594; cv=none; d=zohomail.com; s=zohoarc; b=Uqa4aIBVU01uRG/CzOfbgWsbRkQTVmRQT0feZjtp6m5IB6mr7RzrD6N4BVIpXztJjZ53MEELU1w1iZ7CUs7zVrARPxPopG6USO6ZclIS85U+vYnjU1GIJA3tNLcoVUosnQdVG4F9Bp0P+iCtBqZBFNump7Pw7L2+w60EhvaT6VI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1687376594; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=gDDm9mLC5RCOTcJD8XxpUVvDwnW2092vMb4yslw7dK8=; b=JwrUsIX+KuwIBvKUS+4A12pNXAG39u+Ico19qwxboe25Fe3h6pETuoEOdNWilEAxyUB2gPPnmTCuZkvgDg6IQlqaOsP8a0FIfyTgYkN6C/lAsABX3nkIvp62otEIPLy8aew1HpcMlxJoNBaTkG74lMH5NEC89LEYVYE1G11eEt4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1687376594592280.97987454702775; Wed, 21 Jun 2023 12:43:14 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-48-J3W2altmNu6YWid9koiwkQ-1; Wed, 21 Jun 2023 15:43:11 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6CA788AB381; Wed, 21 Jun 2023 19:43:07 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 806B6C1ED96; Wed, 21 Jun 2023 19:43:04 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 56EF31946587; Wed, 21 Jun 2023 19:43:04 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id EF1521946586 for ; Wed, 21 Jun 2023 19:43:03 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id DF59514682F9; Wed, 21 Jun 2023 19:43:03 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.17.148]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B4BBB14682F8; Wed, 21 Jun 2023 19:43:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1687376593; h=from:from:sender:sender: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:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=gDDm9mLC5RCOTcJD8XxpUVvDwnW2092vMb4yslw7dK8=; b=dklVUORH6hRNCp/TCNbunAInbJkCV9FfvtP33G1vnbqh92N+Zxv6KTxMIhN1uQVJR55SCv HaNAqk9yJnWG7fWQcY6pzWc2i03aPbCNvv96RQt6NagsU+S1/lqkMyyORJvFq9f7OLcESP Gnc3DSQ6UCamqWV8HIDLwnBvMCyVlXU= X-MC-Unique: J3W2altmNu6YWid9koiwkQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH v2] run: add ability to set selinux context Date: Wed, 21 Jun 2023 14:43:03 -0500 Message-Id: <20230621194303.207498-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: eskultet@redhat.com Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1687376595280100001 Content-Type: text/plain; charset="utf-8"; x-default="true" When running libvirt from the build directory with the 'run' script, it will run as unconfined_t. This can result in unexpected behavior when selinux is enforcing due to the fact that the selinux policies are written assuming that libvirt is running with the system_u:system_r:virtd_t context. This patch adds a new --selinux option to the run script. When this option is specified, it will launch the specified binary using the 'runcon' utility to set its selinux context to the one mentioned above. Since this may require root privileges, setting the selinux context is not the default behavior and must be enabled with the command line switch. Note that this uses argparse to parse the new option, but it does so in a very limited way in order to avoid interfering with any arguments that the user might want to pass on to libvirt. For example, we do not provide a `--help` option for the run script. Signed-off-by: Jonathon Jongsma Reviewed-by: Martin Kletzander --- I sent a version of this a couple months ago and Erik made a few comments and then I kind of forgot about it for a little while. Re-sending now with a couple minor changes changes in v2: - rebased to master - fixed to properly restore context of binary after execution if the systemd unit file is not currently running. - disabled abbreviated versions of options run.in | 100 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/run.in b/run.in index c6d3411082..869f074d71 100644 --- a/run.in +++ b/run.in @@ -40,9 +40,11 @@ # # ---------------------------------------------------------------------- =20 +import argparse import os import os.path import random +import shutil import signal import sys import subprocess @@ -59,15 +61,20 @@ def prepend(env, varname, extradir): =20 here =3D "@abs_builddir@" =20 -if len(sys.argv) < 2: - print("syntax: %s BINARY [ARGS...]" % sys.argv[0], file=3Dsys.stderr) +parser =3D argparse.ArgumentParser(add_help=3DFalse, allow_abbrev=3DFalse) +parser.add_argument('--selinux', + action=3D'store_true', + help=3D'Run in the appropriate selinux context') + +opts, args =3D parser.parse_known_args() + +if len(args) < 1: + print("syntax: %s [--selinux] BINARY [ARGS...]" % sys.argv[0], file=3D= sys.stderr) sys.exit(1) =20 -prog =3D sys.argv[1] -args =3D sys.argv[1:] +prog =3D args[0] env =3D os.environ =20 - prepend(env, "LD_LIBRARY_PATH", os.path.join(here, "src")) prepend(env, "PKG_CONFIG_PATH", os.path.join(here, "src")) prepend(env, "PATH", os.path.join(here, "tools")) @@ -130,10 +137,25 @@ def change_unit(name, action): return ret =3D=3D 0 =20 =20 +def chcon(path, user, role, type): + print("Setting file context of {} to u=3D{}, r=3D{}, t=3D{}...".format= (progpath, + user, + role, + type)) + ret =3D subprocess.call(["chcon", "-u", user, "-r", role, "-t", type, = path]) + return ret =3D=3D 0 + + +def restorecon(path): + print("Restoring selinux context for {}...".format(path)) + ret =3D subprocess.call(["restorecon", path]) + return ret =3D=3D 0 + + try_stop_units =3D [] if is_systemd_host(): maybe_stopped_units =3D [] - for arg in sys.argv: + for arg in args: name =3D os.path.basename(arg) if is_modular_daemon(name): # Only need to stop libvirtd or this specific modular unit @@ -149,11 +171,10 @@ if is_systemd_host(): if is_unit_active(unit): try_stop_units.append(unit) =20 -if len(try_stop_units) =3D=3D 0: +if len(try_stop_units) =3D=3D 0 and not opts.selinux: # Run the program directly, replacing ourselves os.execvpe(prog, args, env) else: - print("Temporarily stopping systemd units...") stopped_units =3D [] =20 def sighandler(signum, frame): @@ -164,12 +185,48 @@ else: signal.signal(signal.SIGQUIT, sighandler) =20 try: - for unit in try_stop_units: - print(" > %s" % unit) - if not change_unit(unit, "stop"): - raise Exception("Unable to stop '%s'" % unit) - - stopped_units.append(unit) + dorestorecon =3D False + progpath =3D shutil.which(prog) + if len(try_stop_units): + print("Temporarily stopping systemd units...") + + for unit in try_stop_units: + print(" > %s" % unit) + if not change_unit(unit, "stop"): + raise Exception("Unable to stop '%s'" % unit) + + stopped_units.append(unit) + + if opts.selinux: + # if using a wrapper command like 'gdb', setting the selinux + # context won't work because the wrapper command will not be a + # valid entrypoint for the virtd_t context + if os.path.basename(prog) not in ["libvirtd", *modular_daemons= ]: + raise Exception("'{}' is not recognized as a valid daemon.= " + "Selinux process context can only be set w= hen " + "executing a daemon directly without wrapp= er " + "commands".format(prog)) + + if not progpath: + raise Exception("Can't find executable {} for selinux labe= ling" + .format(prog)) + + if not progpath.startswith(os.path.abspath(here)): + raise Exception("Refusing to change selinux context of fil= e " + "'{}' outside build directory" + .format(progpath)) + + # selinux won't allow us to transition to the virtd_t context = from + # e.g. the user_home_t context (the likely label of the local + # executable file) + if not chcon(progpath, "system_u", "object_r", "virtd_exec_t"): + raise Exception("Failed to change selinux context of binar= y") + dorestorecon =3D True + + args =3D ['runcon', + '-u', 'system_u', + '-r', 'system_r', + '-t', 'virtd_t', *args] =20 print("Running '%s'..." % str(" ".join(args))) ret =3D subprocess.call(args, env=3Denv) @@ -178,9 +235,12 @@ else: except Exception as e: print("%s" % e, file=3Dsys.stderr) finally: - print("Re-starting original systemd units...") - stopped_units.reverse() - for unit in stopped_units: - print(" > %s" % unit) - if not change_unit(unit, "start"): - print(" ! unable to restart %s" % unit, file=3Dsys.stderr) + if len(stopped_units): + print("Re-starting original systemd units...") + stopped_units.reverse() + for unit in stopped_units: + print(" > %s" % unit) + if not change_unit(unit, "start"): + print(" ! unable to restart %s" % unit, file=3Dsys.std= err) + if dorestorecon: + restorecon(progpath) --=20 2.40.1