From nobody Mon Jun 29 19:26:04 2026 X-Original-To: dev-commits-src-branches@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 4gpx8Y0W3xz6jjcs for ; Mon, 29 Jun 2026 19:26:05 +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 4gpx8X4Q2Pz40dD for ; Mon, 29 Jun 2026 19:26:04 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1782761164; 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=MD6au5c9B9xnimmvuFc+YlU9eiAYVbkXqOe/ov932YA=; b=u75yZRQaXfSir+s0OMibABIP9w98fCEEpr8BVp7soUNd4QxAF9Ei/CRRlQyKHtt3APUIi7 dG/oqTMVuG1n5YyWs6WnIWT0DKTwL36GzP0MKgjXcYruwF8ThEXqVaosChLPLgsIbLSdJS WWs+pggifCCCTudNv3zvRFEWxaxMdQpiOtTUO5hNAYUYGGGRC7PrU3eRc2yHISEx5WZJtF 5Am5j1s62KEf4jiMKV3GDu8iQifvhjbvO8rM+GbuPnxteZUSSAV2bpJSNtVOJOEayEqQKz lLKvpKLpiK1vGVXfQTf8A6aDGUoRDgxfjDHrcgQi3606unNZmR/yXN/AHACqsQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1782761164; a=rsa-sha256; cv=none; b=t1VSWLg3BpyPIbRvBmWmIbMYkxH6yVX7VF5aQbHUf6x2sPL/lA/yEx56Yrd9ra7lOzG8IL qmDihA92qZdePdJ9PTBPNVnixTBrJZO8niDCMpEfyjQUlxKKJqa4AFfsoHeZoJQxMEOQfw 42gqNBNRX4Z1r4HXgn+6c1Nwm6aMhl5wu8LYffcUTdkF1LH4h3UPV8fGOMgkh2r+gGKsBI 3frECVQM2/NJwxs2Mf8mnw3QXFycBhV01x0htUMA7JJy211gR74iLG+BH2ZdFal62REeg9 Hx6/Gwjgfd9HCiWsJjc2hPwyflDM/qM9FBHsug7kpfoyXlFJdRCXODwN3uZngw== 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=1782761164; 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=MD6au5c9B9xnimmvuFc+YlU9eiAYVbkXqOe/ov932YA=; b=bdLSRRsTd/CrpZp3cx9quzmLOtOIOln5GWznLZ1/fOIkJcaM6b/OdYZ458znR8WMwSLXeZ x95h1THkzVPR4rPUbk0oGNNX0Ie7Egwa0bVcqWE59EZZqZr9HSkvQxgo1H/RocAIzdBU59 CSKr3T8eoymvutVbmfdwINZUVXnEbcHhoYGtFJZS9ZsLNi/Xk0cdAVrJl+OFoiutrDZB1x lzMItNNxObAlcbqS9YIK7Zht+xOJbM/sn1cULMeR07qAfrPz5zseR9AHsoHF8xdpg6SYI/ JCyBNNMVgiUfCtjL2605AorM2/hk/bf596WsLOP+Pd4F52r3+6J6/YuK5vzvnA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gpx8X2jRcz19fr for ; Mon, 29 Jun 2026 19:26:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 208c9 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 29 Jun 2026 19:26:04 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Olivier Certner Subject: git: ac9d12f27abf - stable/15 - MAC/do: Serialize installing/modifying some jail's configuration List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@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: ac9d12f27abf57bc27212f3215445b1b6d8cc67f Auto-Submitted: auto-generated Date: Mon, 29 Jun 2026 19:26:04 +0000 Message-Id: <6a42c6cc.208c9.23b48a2f@gitrepo.freebsd.org> The branch stable/15 has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=ac9d12f27abf57bc27212f3215445b1b6d8cc67f commit ac9d12f27abf57bc27212f3215445b1b6d8cc67f Author: Olivier Certner AuthorDate: 2026-04-29 18:32:56 +0000 Commit: Olivier Certner CommitDate: 2026-06-29 19:23:55 +0000 MAC/do: Serialize installing/modifying some jail's configuration See the immediately preceding commit for explanations on what this is fixing. When setting 'mac.do' to 'inherit' on a jail with 'mac.do.rules' and 'mac.do.exec_paths' also specified in the same call, ensure that the check that these passed parameters are the same as those to be inherited is atomic with respect to enabling the inheritance (i.e., removing the jail's 'struct conf' object). (See previous commit "MAC/do: Fix the recent logic to set jail parameters, make it more tolerant" as for why this check exists.) Because we currently only modify a single configuration object per transaction, we introduce the parse_and_commit_conf() wrapper around parse_and_set_conf() to remove duplicated code that would ensue from calling the latter directly, namely, releasing the 'mac_do_rwl' lock and freeing the old configuration object (if any). Taking the 'mac_do_rwl' lock for writing as a way to freeze all accesses to mac_do(4) configurations was deemed too thin an operation to be worth wrapping. Reviewed by: bapt (older version) 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 4c98f7a0025eea550ecf6f93f818cd03c6ac0fd5) --- sys/security/mac_do/mac_do.c | 99 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/sys/security/mac_do/mac_do.c b/sys/security/mac_do/mac_do.c index c493c47a84df..9ca6874ce145 100644 --- a/sys/security/mac_do/mac_do.c +++ b/sys/security/mac_do/mac_do.c @@ -1406,10 +1406,10 @@ set_conf(struct prison *const pr, struct conf *const conf) * * Destroys the 'osd_jail_slot' slot of the passed jail. */ -static void -remove_conf(struct prison *const pr) +static struct conf * +remove_conf_locked(struct prison *const pr) { - set_conf(pr, NULL); + return (set_conf_locked(pr, NULL, NULL)); } static struct conf * @@ -1483,11 +1483,15 @@ clone_exec_paths(struct exec_paths *const dst, * parameters are copied from those of the passed model configuration (which is * expected to be the currently applicable configuration, i.e., that of the * closest ancestor jail that has one). + * + * 'mac_do_rml' needs to be write-locked (and stays so). 'old_conf' serves to + * return, on no error, the old configuration with a reference (which must be + * eventually freed). */ static int parse_and_set_conf(struct prison *const pr, const char *const rules_string, const char *const exec_paths_string, const struct conf *const model_conf, - struct parse_error **const parse_error) + struct conf **const old_conf, struct parse_error **const parse_error) { struct conf *const conf = new_conf(); int error = 0; @@ -1513,7 +1517,8 @@ parse_and_set_conf(struct prison *const pr, const char *const rules_string, clone_exec_paths(&conf->exec_paths, &model_conf->exec_paths); - set_conf(pr, conf); + MPASS(error == 0); + *old_conf = set_conf_locked(pr, conf, osd_reserve(osd_jail_slot)); MPASS(error == 0 && *parse_error == NULL); out: @@ -1524,6 +1529,30 @@ error: goto out; } +/* + * Calls parse_and_set_conf() and closes the current configuration transaction. + * + * Closes the transaction by unlocking 'mac_do_rml' and releasing the old + * configuration returned by parse_and_set_conf(). + */ +static int +parse_and_commit_conf(struct prison *const pr, const char *const rules_string, + const char *const exec_paths_string, const struct conf *const model_conf, + struct parse_error **const parse_error) +{ + struct conf *old_conf; + int error; + + error = parse_and_set_conf(pr, rules_string, exec_paths_string, + model_conf, &old_conf, parse_error); + rm_wunlock(&mac_do_rml); + + if (error == 0 && old_conf != NULL) + drop_conf(old_conf); + return (error); +} + + static int mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS) { @@ -1533,14 +1562,23 @@ mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS) struct parse_error *parse_error = NULL; int error; - conf = find_conf(pr, NULL); + if (req->newptr != NULL) { + rm_wlock(&mac_do_rml); + conf = find_conf_locked(pr, NULL); + } else + conf = find_conf(pr, NULL); strlcpy(buf, conf->rules.string, MAX_RULE_STRING_SIZE); error = sysctl_handle_string(oidp, buf, MAX_RULE_STRING_SIZE, req); - if (error != 0 || req->newptr == NULL) + if (req->newptr == NULL) + goto out; + if (error != 0) { + rm_wunlock(&mac_do_rml); goto out; + } - error = parse_and_set_conf(pr, buf, NULL, conf, &parse_error); + /* Unlocks 'mac_do_rml'. */ + error = parse_and_commit_conf(pr, buf, NULL, conf, &parse_error); if (error != 0) { if (print_parse_error) printf("MAC/do: Parse error at index %zu: %s\n", @@ -1573,14 +1611,23 @@ mac_do_sysctl_exec_paths(SYSCTL_HANDLER_ARGS) struct parse_error *parse_error = NULL; int error; - conf = find_conf(pr, NULL); + if (req->newptr != NULL) { + rm_wlock(&mac_do_rml); + conf = find_conf_locked(pr, NULL); + } else + conf = find_conf(pr, NULL); strlcpy(buf, conf->exec_paths.exec_paths_str, MAX_EXEC_PATHS_SIZE); error = sysctl_handle_string(oidp, buf, MAX_EXEC_PATHS_SIZE, req); - if (error != 0 || req->newptr == NULL) + if (req->newptr == NULL) goto out; + if (error != 0) { + rm_wunlock(&mac_do_rml); + goto out; + } - error = parse_and_set_conf(pr, NULL, buf, conf, &parse_error); + /* Unlocks 'mac_do_rml'. */ + error = parse_and_commit_conf(pr, NULL, buf, conf, &parse_error); if (error != 0) { if (print_parse_error) printf("MAC/do: Parse error at index %zu: %s\n", @@ -1809,14 +1856,17 @@ mac_do_jail_set(void *obj, void *data) } if (jsys == JAIL_SYS_INHERIT) { + struct conf *old_conf = NULL; + error = 0; + rm_wlock(&mac_do_rml); if (!absent_or_empty_rules || !absent_or_empty_exec_paths) { /* * Some values specified. Check that they match the * ones we are going to inherit. */ - model_conf = find_conf(pr->pr_parent, NULL); + model_conf = find_conf_locked(pr->pr_parent, NULL); if (strcmp(model_conf->rules.string, rules_string) != 0) { error = EINVAL; @@ -1840,23 +1890,25 @@ mac_do_jail_set(void *obj, void *data) } if (error == 0) - /* - * There's no TOCTOU problem here as the removal of the - * current jail's configuration commutes with changing - * the inherited configuration we checked against. - */ - remove_conf(pr); + old_conf = remove_conf_locked(pr); + + rm_wunlock(&mac_do_rml); + + if (old_conf != NULL) + drop_conf(old_conf); return (error); } model_conf = NULL; + /* Freeze configuration accesses. */ + rm_wlock(&mac_do_rml); switch (jsys) { case JAIL_SYS_DISABLE: /* * mac_do(4) is disabled iff one of the parameter's string is - * empty. The parse_and_set_conf() call below treats passing + * empty. The parse_and_commit_conf() call below treats passing * NULL for a parameter as a flag to copy its value from the * relevant ancestor jail's configuration, so we have to watch * for the final result having an empty parameter if no @@ -1878,7 +1930,7 @@ mac_do_jail_set(void *obj, void *data) * values). */ if (rules_string == NULL || exec_paths_string == NULL) - model_conf = find_conf(pr, NULL); + model_conf = find_conf_locked(pr, NULL); /* If both are absent, we have to examine if, in the * currently applicable configuration, one of the * parameters, which we are going to copy, is @@ -1896,16 +1948,17 @@ mac_do_jail_set(void *obj, void *data) break; case JAIL_SYS_NEW: - /* See the comment before the call to find_conf() above. */ + /* See the comment before the same test above. */ if (rules_string == NULL || exec_paths_string == NULL) - model_conf = find_conf(pr, NULL); + model_conf = find_conf_locked(pr, NULL); break; default: __assert_unreachable(); } - error = parse_and_set_conf(pr, rules_string, exec_paths_string, + /* Unlocks 'mac_do_rml'. */ + error = parse_and_commit_conf(pr, rules_string, exec_paths_string, model_conf, &parse_error); if (model_conf != NULL) drop_conf(model_conf);