From nobody Mon Jun 29 19:26:03 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gpx8W5gSXz6jjcq for ; Mon, 29 Jun 2026 19:26:03 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gpx8W2rzdz40g1 for ; Mon, 29 Jun 2026 19:26:03 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1782761163; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4Trtu/2/7HGuDOk3YuMjInne6m9UaGqPOde34IN8qmM=; b=V7H06ZrgA/EihgOM1qpHFfv6i8jvUtb132eVvxPKkM+Jngf90A7SqrdcRPcGQEqzsciZKD fjyc7bEf7X6UJpbiFBbEY4GbN8l8Ve7StmJYJ9weOPJmD89X0iJkwDToPwPFLAThE5THbY yICAJi1TTt4p/TlFx3LStkATWRQmJvNS55qsIWoEJSN43RJpa2VBBKb6pJyyhh7ldsobs0 zQWgY6i1eehV327FOB+n42F1JbIrSdL7kRXFZA1yXSrzDlrBBJ5F3Dn0A855YkdCD5kJvJ 7RjlfQVXR8V1R8VkbZn+bSXJQhTEZ2lZOkaj/TLADur6jRU7j1Q4lnnkq+Hl0A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1782761163; a=rsa-sha256; cv=none; b=cuIMcMLtadn/c8hQHQJCV8Ox17qpUnRotvV5a4rsnt1Wg+p+NX+zk+jHSi9LAS3huLwvWP fXcbmHyWjGp8pnggsTlyvF0+5lBuVq9nRgfIIseTVQeo3Cd3RCDvnwV91YkZ9djKqHHOpp /f0XJepctbnkLPsDg+Mbestl4ZoG+uIbxHEwCPvdbb29Q7RGD6neaUtXp9At+AUgkLHygy /s7a49HzyP1nyHL8nKXHe+9MT/YqWaZONfyIAE6NERodEtGzh4HJPJzJ7P6/RMXN4+mhr5 +uNWZ0Y3KYB1OosM7kC9o5//6SSsurt+zQ2ysDA6dotp/g1aL7HgHzuLTX1NnA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1782761163; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4Trtu/2/7HGuDOk3YuMjInne6m9UaGqPOde34IN8qmM=; b=vtVd41+nMZYwnUop7unHSKa95jn3o1ivqIk0Ig1qfvhxKI+JCjpYLggBoP7S9swiMX6NCu tGfgv9S5dFDRsp4E8b4WL3GbHu00TYjblQfhtqIHuw35MWnhFiMfhdZLkS0U2Qu0VLyjAZ wBS2n0TmjpjpS+X6qzttJQDQuEg9EEblnBHP3hojH1R3I4ZAF2Nb08JIkAgoWzfkCy/94S NLTsiN1WzAr+lM8B2SCJWthG8SLN0n9hAqDF70nhWAYJ6lD7EHiqEOtEv/CQQ6u3tIGPo/ pGoSdOLM9lWxYDyK7jeF7vA/Hk14jn/2uEf5j2qVRepZQQcZCRVVlDnIUJR33Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gpx8W1snNz198K for ; Mon, 29 Jun 2026 19:26:03 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 21b7a by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 29 Jun 2026 19:26:03 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Olivier Certner Subject: git: d344d17c24dd - stable/15 - MAC/do: Support for atomically modifying configurations List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: olce X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: d344d17c24dd4dfa876706032799a2d2853ce74a Auto-Submitted: auto-generated Date: Mon, 29 Jun 2026 19:26:03 +0000 Message-Id: <6a42c6cb.21b7a.2adb93e@gitrepo.freebsd.org> The branch stable/15 has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=d344d17c24dd4dfa876706032799a2d2853ce74a commit d344d17c24dd4dfa876706032799a2d2853ce74a Author: Olivier Certner AuthorDate: 2026-04-29 16:28:44 +0000 Commit: Olivier Certner CommitDate: 2026-06-29 19:23:54 +0000 MAC/do: Support for atomically modifying configurations As mentioned in previous commits "MAC/do: parse_and_set_conf(): Require the model configuration" and "MAC/do: Sequential consistency for configuration retrieval", the introduction of the "executable path" feature, more fundamentally, the fact that there is now more than one per-jail parameter and that parameters can be independently modified or copied, causes an atomicity problem in case of concurrent accesses to of a jail's applicable configuration. Partially modifying a configuration is indeed akin to a read-modify-write operation, where the read is either to the current or an inherited configuration. More precisely, once pointed to by a jail, a configuration object is immutable, and changing the jail's configuration means making the jail point to another configuration object. To change a jail's configuration, a new configuration object is thus built, and if only some parameters have been explicitly specified, those that have not been are set by copying the corresponding values from an existing configuration object (in case of partial modification of the existing configuration, from the original configuration object that is going to be replaced; in case of breakage of inheritance or at jail creation, from the applicable configuration object, which is on an ancestor jail). This process is not immune to concurrent modifications because nothing prevents changes of configurations between reading existing values and setting the new configuration. Thus, some other thread could change the value of a parameter after a copy of it has been made into the new object but before that copy is actually installed, which effectively will erase the other thread's modification. To avoid this, we introduce support for serializing configuration changes on a given jail. To this end, we move the jail climbing process from find_conf() into find_conf_locked(), and make the former call the latter in a read-locked section. Similarly, we isolate setting a configuration in the new set_conf_locked() function, and make set_conf() call it inside a write-locked section. The new *_unlocked() variants make it possible to prevent any configuration access between determining and reading an applicable configuration, computing from it a new configuration object and finally setting it, by holding a write lock over the whole process (there is a trade-off here, as read-mostly locks cannot be upgraded), effectively making it atomic and realizing full sequential consistency of configuration changes. Also, the 'mac_do_rm' global read-mostly lock is made sleepable so that it can be write-locked over sysctl_handle*() functions or memory allocations (eases implementation, at the expense of a potential loss of concurrency which is most probably irrelevant). No functional change (intended) at this point. Reviewed by: bapt Fixes: 9818224174c4 ("MAC/do: Executable paths feature (GSoC 2025's final state)") MFC after: 1 month Sponsored by: The FreeBSD Foundation Pull Request: https://ron-dev.freebsd.org/FreeBSD/src/pulls/38 (cherry picked from commit 0db7f110cb810b7aa6d29df221edf9091d66b58a) --- sys/security/mac_do/mac_do.c | 64 +++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/sys/security/mac_do/mac_do.c b/sys/security/mac_do/mac_do.c index 0c1bf101d3ee..c493c47a84df 100644 --- a/sys/security/mac_do/mac_do.c +++ b/sys/security/mac_do/mac_do.c @@ -1246,13 +1246,12 @@ drop_conf(struct conf *const conf) * one, establishing inheritance from higher up). */ static struct conf * -find_conf(struct prison *const pr, struct prison **const hpr) +find_conf_locked(struct prison *const pr, struct prison **const hpr) { struct prison *cpr, *ppr; /* Current and parent. */ struct conf *conf; - struct rm_priotracker rmpt; - rm_rlock(&mac_do_rml, &rmpt); + rm_assert(&mac_do_rml, RA_LOCKED); /* * We do not need to take any locks here to climb the prison tree as * either the start prison ('pr') is that of the current thread (and our @@ -1280,11 +1279,20 @@ find_conf(struct prison *const pr, struct prison **const hpr) } hold_conf(conf); - rm_runlock(&mac_do_rml, &rmpt); - if (hpr != NULL) *hpr = cpr; + return (conf); +} + +static struct conf * +find_conf(struct prison *const pr, struct prison **const hpr) +{ + struct conf *conf; + struct rm_priotracker rmpt; + rm_rlock(&mac_do_rml, &rmpt); + conf = find_conf_locked(pr, hpr); + rm_runlock(&mac_do_rml, &rmpt); return (conf); } @@ -1332,22 +1340,29 @@ dealloc_jail_osd(void *const value) } /* - * Assign an already-built configuration to a jail. + * Sets a mac_do(4) configuration on a jail. * - * Takes care of write-locking 'mac_do_rm', which should be unlocked on entry - * and will be unlocked on exit. + * 'conf' is the new conf to set (can be NULL), and an additional reference will + * be taken on it to represent the jail holding it (if not NULL). 'rsv' must + * have been allocated through osd_reserve() (if 'conf' is not NULL; else can + * be NULL). + * + * The previous configuration on the jail (or NULL) is returned (with an + * associated reference if not NULL). */ -static void -set_conf(struct prison *const pr, struct conf *const conf) +static struct conf * +set_conf_locked(struct prison *const pr, struct conf *const conf, + void **const rsv) { - void **const rsv = conf != NULL ? osd_reserve(osd_jail_slot) : NULL; struct conf *old_conf; int error __diagused; + KASSERT(conf == NULL || rsv != NULL, + ("MAC/do: OSD reserve needed to avoid allocating memory")); + rm_assert(&mac_do_rml, RA_WLOCKED); + if (conf != NULL) hold_conf(conf); - - rm_wlock(&mac_do_rml); old_conf = osd_jail_get_unlocked(pr, osd_jail_slot); error = osd_jail_set_reserved(pr, osd_jail_slot, rsv, conf); KASSERT(error == 0, ("MAC/do: osd_jail_set_reserved() failed " @@ -1358,8 +1373,27 @@ set_conf(struct prison *const pr, struct conf *const conf) * destructor since we've just put NULL into the slot. */ osd_jail_del(pr, osd_jail_slot); - rm_wunlock(&mac_do_rml); + return (old_conf); +} +/* + * Immediately replace the jail's configuration. + * + * To be used only if the configuration to set does not depend in any way on the + * currently applicable configuration. + * + * Takes care of write-locking 'mac_do_rml', which should be unlocked on entry + * and will be unlocked on exit. + */ +static void +set_conf(struct prison *const pr, struct conf *const conf) +{ + void **const rsv = conf != NULL ? osd_reserve(osd_jail_slot) : NULL; + struct conf *old_conf; + + rm_wlock(&mac_do_rml); + old_conf = set_conf_locked(pr, conf, rsv); + rm_wunlock(&mac_do_rml); if (old_conf != NULL) drop_conf(old_conf); } @@ -2542,7 +2576,7 @@ mac_do_init(struct mac_policy_conf *mpc) struct conf *const default_conf = new_default_conf(); struct prison *pr; - rm_init(&mac_do_rml, "mac_do(4)"); + rm_init_flags(&mac_do_rml, "mac_do(4)", RM_SLEEPABLE); osd_jail_slot = osd_jail_register(dealloc_jail_osd, osd_methods); set_conf(&prison0, default_conf);