From nobody Tue May 13 13:33:48 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1536572283970759.7849756770349; Mon, 10 Sep 2018 02:38:03 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AA926C058CA0; Mon, 10 Sep 2018 09:38:02 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6952E5D9C7; Mon, 10 Sep 2018 09:38:02 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 154334A460; Mon, 10 Sep 2018 09:38:02 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w8A9b259030839 for ; Mon, 10 Sep 2018 05:37:02 -0400 Received: by smtp.corp.redhat.com (Postfix) id 9C0B310EE839; Mon, 10 Sep 2018 09:37:02 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.192]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3CC9910EE836 for ; Mon, 10 Sep 2018 09:37:02 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Mon, 10 Sep 2018 11:36:17 +0200 Message-Id: <34c1c3c209d5b2f2cf9f5811098c15d62f4d452e.1536571504.git.mprivozn@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v4 16/23] security_manager: Introduce metadata locking APIs X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 10 Sep 2018 09:38:03 +0000 (UTC) X-ZohoMail: RDMRC_0 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Two new APIs are added so that security driver can lock and unlock paths it wishes to touch. These APIs are not for other drivers to call but security drivers (DAC and SELinux). That is the reason these APIs are not exposed through our libvirt_private.syms file. Three interesting things happen in this commit. The first is the global @lockManagerMutex. Unfortunately, this has to exist so that there is only on thread talking to virtlockd at a time. If there were more threads and one of them closed the connection prematurely, it would cause virtlockd killing libvirtd. Instead of complicated code that would handle that, let's have a mutex and keep the code simple. The second interesting thing is keeping connection open between lock and unlock API calls. This is achieved by duplicating client FD and keeping it open until unlock is called. This trick is used by regular disk content locking code when the FD is leaked to qemu. Finally, the third thing is polling implemented at client side. Since virtlockd has only one thread that handles locking requests, all it can do is either acquire lock or error out. Therefore, the polling has to be implemented in client. The polling is capped at 60 second timeout, which should be plenty since the metadata lock is held only for a fraction of a second. Signed-off-by: Michal Privoznik Reviewed-by: John Ferlan --- src/security/security_manager.c | 135 ++++++++++++++++++++++++++++++++++++= ++++ src/security/security_manager.h | 7 +++ 2 files changed, 142 insertions(+) diff --git a/src/security/security_manager.c b/src/security/security_manage= r.c index 5c8370c159..dd5c3ac7e5 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -29,11 +29,15 @@ #include "virobject.h" #include "virlog.h" #include "locking/lock_manager.h" +#include "virfile.h" +#include "virtime.h" =20 #define VIR_FROM_THIS VIR_FROM_SECURITY =20 VIR_LOG_INIT("security.security_manager"); =20 +virMutex lockManagerMutex =3D VIR_MUTEX_INITIALIZER; + struct _virSecurityManager { virObjectLockable parent; =20 @@ -43,6 +47,7 @@ struct _virSecurityManager { void *privateData; =20 virLockManagerPluginPtr lockPlugin; + int fd; }; =20 static virClassPtr virSecurityManagerClass; @@ -57,6 +62,7 @@ void virSecurityManagerDispose(void *obj) mgr->drv->close(mgr); =20 virObjectUnref(mgr->lockPlugin); + VIR_FORCE_CLOSE(mgr->fd); =20 VIR_FREE(mgr->privateData); } @@ -109,6 +115,7 @@ virSecurityManagerNewDriver(virSecurityDriverPtr drv, mgr->flags =3D flags; mgr->virtDriver =3D virtDriver; VIR_STEAL_PTR(mgr->privateData, privateData); + mgr->fd =3D -1; =20 if (drv->open(mgr) < 0) goto error; @@ -1263,3 +1270,131 @@ virSecurityManagerRestoreTPMLabels(virSecurityManag= erPtr mgr, =20 return 0; } + + +static virLockManagerPtr +virSecurityManagerNewLockManager(virSecurityManagerPtr mgr, + const char * const *paths, + size_t npaths) +{ + virLockManagerPtr lock; + virLockManagerParam params[] =3D { + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UUID, + .key =3D "uuid", + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_STRING, + .key =3D "name", + .value =3D { .cstr =3D "libvirtd-sec" }, + }, + { .type =3D VIR_LOCK_MANAGER_PARAM_TYPE_UINT, + .key =3D "pid", + .value =3D { .iv =3D getpid() }, + }, + }; + const unsigned int flags =3D 0; + size_t i; + + if (virGetHostUUID(params[0].value.uuid) < 0) + return NULL; + + if (!(lock =3D virLockManagerNew(virLockManagerPluginGetDriver(mgr->lo= ckPlugin), + VIR_LOCK_MANAGER_OBJECT_TYPE_DAEMON, + ARRAY_CARDINALITY(params), + params, + flags))) + return NULL; + + for (i =3D 0; i < npaths; i++) { + if (virLockManagerAddResource(lock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_METAD= ATA, + paths[i], 0, NULL, 0) < 0) + goto error; + } + + return lock; + error: + virLockManagerFree(lock); + return NULL; +} + + +/* How many seconds should we try to acquire the lock before + * giving up. */ +#define LOCK_ACQUIRE_TIMEOUT 60 + +int +virSecurityManagerMetadataLock(virSecurityManagerPtr mgr, + const char * const *paths, + size_t npaths) +{ + virLockManagerPtr lock; + virTimeBackOffVar timebackoff; + int fd =3D -1; + int rv; + int ret =3D -1; + + virMutexLock(&lockManagerMutex); + + if (!(lock =3D virSecurityManagerNewLockManager(mgr, paths, npaths))) + goto cleanup; + + if (virTimeBackOffStart(&timebackoff, 1, LOCK_ACQUIRE_TIMEOUT * 1000) = < 0) + goto cleanup; + while (virTimeBackOffWait(&timebackoff)) { + rv =3D virLockManagerAcquire(lock, NULL, + VIR_LOCK_MANAGER_ACQUIRE_ROLLBACK, + VIR_DOMAIN_LOCK_FAILURE_DEFAULT, &fd); + + if (rv >=3D 0) + break; + + if (virGetLastErrorCode() =3D=3D VIR_ERR_RESOURCE_BUSY) + continue; + + goto cleanup; + } + + if (rv < 0) + goto cleanup; + + mgr->fd =3D fd; + fd =3D -1; + + ret =3D 0; + cleanup: + virLockManagerFree(lock); + VIR_FORCE_CLOSE(fd); + if (ret < 0) + virMutexUnlock(&lockManagerMutex); + return ret; +} + + +int +virSecurityManagerMetadataUnlock(virSecurityManagerPtr mgr, + const char * const *paths, + size_t npaths) +{ + virLockManagerPtr lock; + int fd; + int ret =3D -1; + + /* lockManagerMutex acquired from previous + * virSecurityManagerMetadataLock() call. */ + + fd =3D mgr->fd; + mgr->fd =3D -1; + + if (!(lock =3D virSecurityManagerNewLockManager(mgr, paths, npaths))) + goto cleanup; + + if (virLockManagerRelease(lock, NULL, 0) < 0) + goto cleanup; + + ret =3D 0; + cleanup: + virLockManagerFree(lock); + VIR_FORCE_CLOSE(fd); + virMutexUnlock(&lockManagerMutex); + return ret; +} diff --git a/src/security/security_manager.h b/src/security/security_manage= r.h index c537e1c994..10ebe5cc29 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -199,4 +199,11 @@ int virSecurityManagerSetTPMLabels(virSecurityManagerP= tr mgr, int virSecurityManagerRestoreTPMLabels(virSecurityManagerPtr mgr, virDomainDefPtr vm); =20 +int virSecurityManagerMetadataLock(virSecurityManagerPtr mgr, + const char * const *paths, + size_t npaths); +int virSecurityManagerMetadataUnlock(virSecurityManagerPtr mgr, + const char * const *paths, + size_t npaths); + #endif /* VIR_SECURITY_MANAGER_H__ */ --=20 2.16.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list