From nobody Fri Apr 04 23:25:03 2025 X-Original-To: dev-commits-src-main@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 4ZTvpR4MQTz5sbY9; Fri, 04 Apr 2025 23:25: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 "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ZTvpR3h4Gz3W5D; Fri, 04 Apr 2025 23:25:03 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743809103; 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=titvMm1vrUnWoKYPG2jC1r+afxZ0EDhneD7xNlmq2Mg=; b=M2l9IpC9gxfazvY+ujHLMxjQJny0tHJj4QgzsLpP01r3juyfTtFPF7jnBxED3/CfSQcFRo cDQUfcnOLATd4z1DC5ldwU3/Ye2TmulTppu4phDUFOcA4IIGBquLl0OL2a0utLCRjkdBfN VVxpRlrvOD2s0vZh8yTfBOnhU4zdiIXpm++dEKQ+XvXMJl7ZDPDHhyReQISrVMbHg1WnJT GVsOQNW/lbL5sYcqMhmZxau7sbZrcrN7O/5XIWZDYfCVnUQZXdvBGuWdQ41VnQe9dFfiZX YC2mHpDKpecqan+6z1Cu1Jr7j8SBq+CG0wCcl3xiyCoDB+xZ07przi1Su8XLGw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1743809103; a=rsa-sha256; cv=none; b=OUfwYIa1a91YhLV1Q+AYncLZfFd7oEpZVrJIWqSkmo1G0cFoSOtI2eP8KKWUZVVlWzT1cE B13iR2rn25FL3Ev7uWTv0Fd8gsQ+l8QyH7WwVoZqivxpfWJsSo11VMuPExGrSc13LHpqV+ dBbPl8PFFWqQE1vR78YbsTwCdEY8QTpK7jO4Ea6VyvhCYnCxkKjK5ukY4/UhMiZe1gMDmz N+015408kxtlaMY3zxlUZaqWBaD8e+CXFGb0wg5Pp+h+uIkeO4wQZNVg0dVGdgLbI06bby nWDlHrzDoYYyLGZeuW0Rs4D3R0Ommon5Ioio1cVXGJ/+dXHLt7YfK7kDrbs0EA== 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=1743809103; 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=titvMm1vrUnWoKYPG2jC1r+afxZ0EDhneD7xNlmq2Mg=; b=JafzpYlYTinxdV0tAeiMAO7/S5ogcEA6b5puyS+XLhXhVAEdGjTZxpXM2asllgDHpWi5H2 mOjW0OoRYwQFhiTAMg7a7jMW5Ipebj0L00pFR+x9HNnJ1xBus+id8uf/T5G51mKNGrJR9E yn6l7JX7z1x2bWNNW/g2zQgSOrjWCVPaAFgBL5GKwEpy0bmYrCN/LA830eeJVmf8qnRh41 AAcZT45A/O4znSBT5yGE95FszojZCn9ygD2Iccna1Z1T0lTLKfn2yxRJer9xuLOiQHqaSy DfJr/iFcEQJnZIRmtvdfbVd/D1dfmuwxRob2HGSy5vyc2c98qqqaAwaFgevheg== 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 4ZTvpR300Yz16Sc; Fri, 04 Apr 2025 23:25:03 +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 534NP3BW063241; Fri, 4 Apr 2025 23:25:03 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 534NP385063238; Fri, 4 Apr 2025 23:25:03 GMT (envelope-from git) Date: Fri, 4 Apr 2025 23:25:03 GMT Message-Id: <202504042325.534NP385063238@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 43c1eb894a57 - main - vm_object: Fix handling of wired map entries in vm_object_split() List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 43c1eb894a57ef30562a02708445c512610d4f02 Auto-Submitted: auto-generated The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=43c1eb894a57ef30562a02708445c512610d4f02 commit 43c1eb894a57ef30562a02708445c512610d4f02 Author: Mark Johnston AuthorDate: 2025-04-04 20:29:25 +0000 Commit: Mark Johnston CommitDate: 2025-04-04 23:24:49 +0000 vm_object: Fix handling of wired map entries in vm_object_split() Suppose a vnode is mapped with MAP_PROT and MAP_PRIVATE, mlock() is called on the mapping, and then the vnode is truncated such that the last page of the mapping becomes invalid. The now-invalid page will be unmapped, but stays resident in the VM object to preserve the invariant that a range of pages mapped by a wired map entry is always resident. This invariant is checked by vm_object_unwire(), for example. Then, suppose that the mapping is upgraded to PROT_READ|PROT_WRITE. We will copy the invalid page into a new anonymous VM object. If the process then forks, vm_object_split() may then be called on the object. Upon encountering an invalid page, rather than moving it into the destination object, it is removed. However, this is wrong when the entry is wired, since the invalid page's wiring belongs to the map entry; this behaviour also violates the invariant mentioned above. Fix this by moving invalid pages into the destination object if the map entry is wired. In this case we must not dirty the page, so add a flag to vm_page_iter_rename() to control this. Reported by: syzkaller Reviewed by: dougm, kib MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D49443 --- sys/vm/vm_object.c | 11 ++++++++--- sys/vm/vm_page.c | 16 ++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 4ab20a86e155..c69fd0d1c161 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1597,16 +1597,21 @@ retry: } /* - * The page was left invalid. Likely placed there by + * If the page was left invalid, it was likely placed there by * an incomplete fault. Just remove and ignore. + * + * One other possibility is that the map entry is wired, in + * which case we must hang on to the page to avoid leaking it, + * as the map entry owns the wiring. This case can arise if the + * backing pager is truncated. */ - if (vm_page_none_valid(m)) { + if (vm_page_none_valid(m) && entry->wired_count == 0) { if (vm_page_iter_remove(&pages, m)) vm_page_free(m); continue; } - /* vm_page_iter_rename() will dirty the page. */ + /* vm_page_iter_rename() will dirty the page if it is valid. */ if (!vm_page_iter_rename(&pages, m, new_object, m->pindex - offidxstart)) { vm_page_xunbusy(m); diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index f351f60f833c..f9653f1d1ec9 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -2038,15 +2038,10 @@ vm_page_replace(vm_page_t mnew, vm_object_t object, vm_pindex_t pindex, * * Panics if a page already resides in the new object at the new pindex. * - * Note: swap associated with the page must be invalidated by the move. We - * have to do this for several reasons: (1) we aren't freeing the - * page, (2) we are dirtying the page, (3) the VM system is probably - * moving the page from object A to B, and will then later move - * the backing store from A to B and we can't have a conflict. - * - * Note: we *always* dirty the page. It is necessary both for the - * fact that we moved it, and because we may be invalidating - * swap. + * This routine dirties the page if it is valid, as callers are expected to + * transfer backing storage only after moving the page. Dirtying the page + * ensures that the destination object retains the most recent copy of the + * page. * * The objects must be locked. */ @@ -2087,7 +2082,8 @@ vm_page_iter_rename(struct pctrie_iter *old_pages, vm_page_t m, m->object = new_object; vm_page_insert_radixdone(m, new_object, mpred); - vm_page_dirty(m); + if (vm_page_any_valid(m)) + vm_page_dirty(m); vm_pager_page_inserted(new_object, m); return (true); }