From 569c5a892234428965623aff00d11647dda1938c Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Thu, 29 Apr 2021 02:03:39 -0700 Subject: [PATCH] Kernel: Harden sys$purge Vector usage against OOM. sys$purge() is a bit unique, in that it is probably in the systems advantage to attempt to limp along if we hit OOM while processing the vmobjects to purge. This change modifies the algorithm to observe OOM and continue trying to purge any previously visited VMObjects. --- Kernel/Syscalls/purge.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Kernel/Syscalls/purge.cpp b/Kernel/Syscalls/purge.cpp index 642fc53aab..cc5f7cd125 100644 --- a/Kernel/Syscalls/purge.cpp +++ b/Kernel/Syscalls/purge.cpp @@ -21,12 +21,22 @@ KResultOr Process::sys$purge(int mode) if (mode & PURGE_ALL_VOLATILE) { NonnullRefPtrVector vmobjects; { + KResult result(KSuccess); InterruptDisabler disabler; MM.for_each_vmobject([&](auto& vmobject) { - if (vmobject.is_anonymous()) - vmobjects.append(vmobject); + if (vmobject.is_anonymous()) { + // In the event that the append fails, only attempt to continue + // the purge if we have already appended something successfully. + if (!vmobjects.try_append(vmobject) && vmobjects.is_empty()) { + result = ENOMEM; + return IterationDecision::Break; + } + } return IterationDecision::Continue; }); + + if (result.is_error()) + return result.error(); } for (auto& vmobject : vmobjects) { purged_page_count += vmobject.purge(); @@ -35,12 +45,22 @@ KResultOr Process::sys$purge(int mode) if (mode & PURGE_ALL_CLEAN_INODE) { NonnullRefPtrVector vmobjects; { + KResult result(KSuccess); InterruptDisabler disabler; MM.for_each_vmobject([&](auto& vmobject) { - if (vmobject.is_inode()) - vmobjects.append(static_cast(vmobject)); + if (vmobject.is_inode()) { + // In the event that the append fails, only attempt to continue + // the purge if we have already appended something successfully. + if (!vmobjects.try_append(static_cast(vmobject)) && vmobjects.is_empty()) { + result = ENOMEM; + return IterationDecision::Break; + } + } return IterationDecision::Continue; }); + + if (result.is_error()) + return result.error(); } for (auto& vmobject : vmobjects) { purged_page_count += vmobject.release_all_clean_pages();