From cb45b2c001e8c50369c441207a74473105cfb362 Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Fri, 28 May 2021 03:52:30 -0700 Subject: [PATCH] Kernel: Make AnonymousVMObject::clone() API OOM safe Propagate allocation failure of m_shared_committed_cow_pages, and uncommit previously committed COW pages on failure. This method needs a closer look in terms of error handling, as we will eventually need to rollback all changes on allocation failure. Alternatively we could allocate the anonymous object much earlier and only initialize it once the other steps have succeeded. --- Kernel/VM/AnonymousVMObject.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Kernel/VM/AnonymousVMObject.cpp b/Kernel/VM/AnonymousVMObject.cpp index 576c040ae5..af568710f5 100644 --- a/Kernel/VM/AnonymousVMObject.cpp +++ b/Kernel/VM/AnonymousVMObject.cpp @@ -33,18 +33,25 @@ RefPtr AnonymousVMObject::clone() if (!MM.commit_user_physical_pages(need_cow_pages)) return {}; + // Create or replace the committed cow pages. When cloning a previously // cloned vmobject, we want to essentially "fork", leaving us and the // new clone with one set of shared committed cow pages, and the original // one would keep the one it still has. This ensures that the original // one and this one, as well as the clone have sufficient resources // to cow all pages as needed - m_shared_committed_cow_pages = adopt_ref(*new CommittedCowPages(need_cow_pages)); + m_shared_committed_cow_pages = adopt_ref_if_nonnull(new CommittedCowPages(need_cow_pages)); + + if (!m_shared_committed_cow_pages) { + MM.uncommit_user_physical_pages(need_cow_pages); + return {}; + } // Both original and clone become COW. So create a COW map for ourselves // or reset all pages to be copied again if we were previously cloned ensure_or_reset_cow_map(); + // FIXME: If this allocation fails, we need to rollback all changes. return adopt_ref_if_nonnull(new AnonymousVMObject(*this)); }