From 2fcebfd6a8d04f50622b6843390fdf7c529cd1cb Mon Sep 17 00:00:00 2001 From: Max Wipfli Date: Sun, 6 Jun 2021 22:12:04 +0200 Subject: [PATCH] Kernel: Update intermediate nodes when changing unveil permissions When changing the unveil permissions of a preexisting node, we need to make sure that any intermediate nodes that were created before and should inherit permissions from the updated node are updated properly. This fixes the following bug: unveil("/home/anon/Documents", "r"); unveil("/home", "r"); Now there was a intermediate node for "/home/anon" which still had no permission, even though it should have inherited the permissions from "/home". --- Kernel/Syscalls/unveil.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Kernel/Syscalls/unveil.cpp b/Kernel/Syscalls/unveil.cpp index edfee6d6ca..77dca0fa74 100644 --- a/Kernel/Syscalls/unveil.cpp +++ b/Kernel/Syscalls/unveil.cpp @@ -13,6 +13,17 @@ namespace Kernel { +static void update_intermediate_node_permissions(UnveilNode& root_node, UnveilAccess new_permissions) +{ + for (auto& entry : root_node.children()) { + auto& node = static_cast(*entry.value); + if (node.was_explicitly_unveiled()) + continue; + node.set_metadata({ node.path(), new_permissions, node.was_explicitly_unveiled() }); + update_intermediate_node_permissions(node, new_permissions); + } +} + KResultOr Process::sys$unveil(Userspace user_params) { Syscall::SC_unveil_params params; @@ -96,6 +107,14 @@ KResultOr Process::sys$unveil(Userspace u if (new_permissions & ~matching_node.permissions()) return EPERM; } + + // It is possible that nodes that are "grandchildren" of the matching node have already been unveiled. + // This means that there may be intermediate nodes between this one and the unveiled "grandchildren" + // that inherited the current node's previous permissions. Those nodes now need their permissions + // updated to match the current node. + if (matching_node.permissions() != new_permissions) + update_intermediate_node_permissions(matching_node, (UnveilAccess)new_permissions); + matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true }); return 0; }