From nobody Wed Sep 4 19:58:28 2024 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 4WzYFw5L7Jz5VHC5; Wed, 04 Sep 2024 19:58:28 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4WzYFw4gs4z49jR; Wed, 4 Sep 2024 19:58:28 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1725479908; 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=ybnkLtyE5DHu2n8P/EOhq/A+/9Z3KNbCAR07ZU5Ilw0=; b=jzRw6BsAlLvRg/yUNWHkhdFm9aEQkxzJhUjtH6J6oJ5EkzBIvt6Lo0EFc2egkWEomQOnjr jlt39TS45J0jTgZcY1hWAG0DfHcQcIVDDMSL5SCA6S9fso7uVBC7laOD6yBsyvDv6shh9s ZwPEZqkg4Rsku7KUv4KMzQKqfmQwuuf9QczJR4w4ENaJSwgsV29nDcgACA966QvnVOFmVT Q/d5eYSJKp9BWoyV7pE4A6Y87VH/lhEkd6J9qXcoGzWf5t/rqyWU1v4fRB1bxA1xKzv2TS 0hYFCmpvs2cL+FZ0qc+a30rzeRZaNaT9H/bflxxOPzMToj/qGovOoqdkHS0Jqw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1725479908; a=rsa-sha256; cv=none; b=JtRaPM2/a+tAid/GgoKgVZorKfRM7kY14e/yVCQ7viu35CsUyzyqrK6eqrAkmDtaeYW+Dl qEJWuuxdvsxC1XvC21WnVOzIsL+LEuckbU0tt/kGna53jpkXvfAjXMKv1Wl83kKNVOiNKT PCpmt0ol+T93zj1AUhfflq4aIUMv5VE5BW2SGP0UxBQFjkwMnhiz0KnpGhMChcZEU3wXYl UnLhGKWvD3BOK6YJoL3QtBhD6tH7Hco3y7SmzMSCTeeig+jVutyq00jy2Lm1mJTl98IMbi tNh2iUonMiiEEmZ3jzLEqwW4d8NNs+KEW5+Ldl3nz6508b6z6BgcEaiWHXPvQg== 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=1725479908; 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=ybnkLtyE5DHu2n8P/EOhq/A+/9Z3KNbCAR07ZU5Ilw0=; b=xB5Sxn8KryPNcOWO0PaM3jYRwU50N7FfsurvUIXNv1HVQKW1z+o3RzyDGSMNoUA46cZ5tz lcGXkPRIevzynRaLmPG8gwkueaalYJiVdei3+EvbpzXkiye9F0/qdbDLusSLOqRh0DaPVw F3Jcg7Az4whwRY4AEYVZfzCZz7YkfHDkIZnq2RoyuM0vhXJTOM27FKc6CzGsfhSxzCEKCV yyaa19dfo5zAB1KdFtuFLI60ThxVrTnfbMlX4/8Sval/2pmZVrS4b2pgxUKpPGayIU5dXt 6Zo/fGqc30GuUjW2joP+jJU0pngMAPWWFg/u/TUPnjd8W4BOet4iFhma+FFEeg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (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 did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4WzYFw4HyxzdjR; Wed, 4 Sep 2024 19:58:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 484JwSQC030212; Wed, 4 Sep 2024 19:58:28 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 484JwS9a030209; Wed, 4 Sep 2024 19:58:28 GMT (envelope-from git) Date: Wed, 4 Sep 2024 19:58:28 GMT Message-Id: <202409041958.484JwS9a030209@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Ed Maste Subject: git: abb0a18b690c - releng/13.4 - umtx: shm: Fix use-after-free due to multiple drops of the registry reference 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 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: emaste X-Git-Repository: src X-Git-Refname: refs/heads/releng/13.4 X-Git-Reftype: branch X-Git-Commit: abb0a18b690c3361346c3c3a57485e2acce3421d Auto-Submitted: auto-generated The branch releng/13.4 has been updated by emaste: URL: https://cgit.FreeBSD.org/src/commit/?id=abb0a18b690c3361346c3c3a57485e2acce3421d commit abb0a18b690c3361346c3c3a57485e2acce3421d Author: Olivier Certner AuthorDate: 2024-09-04 14:38:12 +0000 Commit: Ed Maste CommitDate: 2024-09-04 19:14:57 +0000 umtx: shm: Fix use-after-free due to multiple drops of the registry reference umtx_shm_unref_reg_locked() would unconditionally drop the "registry" reference, tied to USHMF_LINKED. This is not a problem for caller umtx_shm_object_terminated(), which operates under the 'umtx_shm_lock' lock end-to-end, but it is for indirect caller umtx_shm(), which drops the lock between umtx_shm_find_reg() and the call to umtx_shm_unref_reg(true) that deregisters the umtx shared region (from 'umtx_shm_registry'; umtx_shm_find_reg() only finds registered shared mutexes). Thus, two concurrent user-space callers of _umtx_op() with UMTX_OP_SHM and flags UMTX_SHM_DESTROY, both progressing past umtx_shm_find_reg() but before umtx_shm_unref_reg(true), would then decrease twice the reference count for the single reference standing for the shared mutex's registration. Reported by: Synacktiv Reviewed by: kib Approved by: emaste (mentor) Security: FreeBSD-SA-24:14.umtx Security: CVE-2024-43102 Security: CAP-01 Sponsored by: The Alpha-Omega Project Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D46126 (cherry picked from commit 62f40433ab47ad4a9694a22a0313d57661502ca1) (cherry picked from commit be7dc4613909e528e8b4ea8aaa3ae3aa62bec1ed) (cherry picked from commit 40615bcae9e7f41ca857c773e804db9bd7269581) Approved by: so Approved by: re (cperciva) --- sys/kern/kern_umtx.c | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 757e3c869683..aac2e505d844 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -4384,39 +4384,49 @@ umtx_shm_free_reg(struct umtx_shm_reg *reg) } static bool -umtx_shm_unref_reg_locked(struct umtx_shm_reg *reg, bool force) +umtx_shm_unref_reg_locked(struct umtx_shm_reg *reg, bool linked_ref) { - bool res; - mtx_assert(&umtx_shm_lock, MA_OWNED); KASSERT(reg->ushm_refcnt > 0, ("ushm_reg %p refcnt 0", reg)); - reg->ushm_refcnt--; - res = reg->ushm_refcnt == 0; - if (res || force) { - if ((reg->ushm_flags & USHMF_LINKED) != 0) { - TAILQ_REMOVE(&umtx_shm_registry[reg->ushm_key.hash], - reg, ushm_reg_link); - LIST_REMOVE(reg, ushm_obj_link); - reg->ushm_flags &= ~USHMF_LINKED; - } + + if (linked_ref) { + if ((reg->ushm_flags & USHMF_LINKED) == 0) + /* + * The reference tied to USHMF_LINKED has already been + * released concurrently. + */ + return (false); + + TAILQ_REMOVE(&umtx_shm_registry[reg->ushm_key.hash], reg, + ushm_reg_link); + LIST_REMOVE(reg, ushm_obj_link); + reg->ushm_flags &= ~USHMF_LINKED; } - return (res); + + reg->ushm_refcnt--; + return (reg->ushm_refcnt == 0); } static void -umtx_shm_unref_reg(struct umtx_shm_reg *reg, bool force) +umtx_shm_unref_reg(struct umtx_shm_reg *reg, bool linked_ref) { vm_object_t object; bool dofree; - if (force) { + if (linked_ref) { + /* + * Note: This may be executed multiple times on the same + * shared-memory VM object in presence of concurrent callers + * because 'umtx_shm_lock' is not held all along in umtx_shm() + * and here. + */ object = reg->ushm_obj->shm_object; VM_OBJECT_WLOCK(object); vm_object_set_flag(object, OBJ_UMTXDEAD); VM_OBJECT_WUNLOCK(object); } mtx_lock(&umtx_shm_lock); - dofree = umtx_shm_unref_reg_locked(reg, force); + dofree = umtx_shm_unref_reg_locked(reg, linked_ref); mtx_unlock(&umtx_shm_lock); if (dofree) umtx_shm_free_reg(reg); @@ -4469,7 +4479,6 @@ umtx_shm_create_reg(struct thread *td, const struct umtx_key *key, if (!chgumtxcnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_UMTXP))) return (ENOMEM); reg = uma_zalloc(umtx_shm_reg_zone, M_WAITOK | M_ZERO); - reg->ushm_refcnt = 1; bcopy(key, ®->ushm_key, sizeof(*key)); reg->ushm_obj = shm_alloc(td->td_ucred, O_RDWR, false); reg->ushm_cred = crhold(cred); @@ -4486,11 +4495,17 @@ umtx_shm_create_reg(struct thread *td, const struct umtx_key *key, *res = reg1; return (0); } - reg->ushm_refcnt++; TAILQ_INSERT_TAIL(&umtx_shm_registry[key->hash], reg, ushm_reg_link); LIST_INSERT_HEAD(USHM_OBJ_UMTX(key->info.shared.object), reg, ushm_obj_link); reg->ushm_flags = USHMF_LINKED; + /* + * This is one reference for the registry and the list of shared + * mutexes referenced by the VM object containing the lock pointer, and + * another for the caller, which it will free after use. So, one of + * these is tied to the presence of USHMF_LINKED. + */ + reg->ushm_refcnt = 2; mtx_unlock(&umtx_shm_lock); *res = reg; return (0);