diff --git a/Kernel/Process.h b/Kernel/Process.h index 50c7e302108..aebd5dc3f8c 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -640,7 +640,7 @@ private: u32 m_execpromises { 0 }; VeilState m_veil_state { VeilState::None }; - UnveilNode m_unveiled_paths { "/", { "/" } }; + UnveilNode m_unveiled_paths { "/", { .full_path = "/", .unveil_inherited_from_root = true } }; WaitQueue& futex_queue(Userspace); HashMap> m_futex_queues; diff --git a/Kernel/Syscalls/unveil.cpp b/Kernel/Syscalls/unveil.cpp index 74f75252c51..8657ecfee08 100644 --- a/Kernel/Syscalls/unveil.cpp +++ b/Kernel/Syscalls/unveil.cpp @@ -109,9 +109,14 @@ int Process::sys$unveil(Userspace user_params) auto it = lexical_path.parts().begin(); auto& matching_node = m_unveiled_paths.traverse_until_last_accessible_node(it, lexical_path.parts().end()); if (it.is_end()) { - if (new_permissions & ~matching_node.permissions()) - return -EPERM; - matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true }); + auto old_permissions = matching_node.permissions(); + // Allow "elevating" the permissions when the permissions are inherited from root (/), + // as that would be the first time this path is unveiled. + if (old_permissions != UnveilAccess::None || !matching_node.permissions_inherited_from_root()) { + if (new_permissions & ~old_permissions) + return -EPERM; + } + matching_node.set_metadata({ matching_node.path(), (UnveilAccess)new_permissions, true, false }); return 0; } @@ -119,7 +124,7 @@ int Process::sys$unveil(Userspace user_params) it, lexical_path.parts().end(), { new_unveiled_path, (UnveilAccess)new_permissions, true }, - [](auto& parent, auto& it) -> Optional { return UnveilMetadata { String::formatted("{}/{}", parent.path(), *it), parent.permissions(), false }; }); + [](auto& parent, auto& it) -> Optional { return UnveilMetadata { String::formatted("{}/{}", parent.path(), *it), parent.permissions(), false, parent.permissions_inherited_from_root() }; }); ASSERT(m_veil_state != VeilState::Locked); m_veil_state = VeilState::Dropped; return 0; diff --git a/Kernel/UnveilNode.h b/Kernel/UnveilNode.h index 3204493482c..36dcb5b268e 100644 --- a/Kernel/UnveilNode.h +++ b/Kernel/UnveilNode.h @@ -41,15 +41,19 @@ enum UnveilAccess { None = 0, }; +struct UnveilNode; + struct UnveilMetadata { String full_path; UnveilAccess permissions { None }; bool explicitly_unveiled { false }; + bool unveil_inherited_from_root { false }; // true if permissions are inherited from the tree root (/). }; struct UnveilNode final : public AK::Trie, UnveilNode> { using AK::Trie, UnveilNode>::Trie; + bool permissions_inherited_from_root() const { return this->metadata_value().unveil_inherited_from_root; } bool was_explicitly_unveiled() const { return this->metadata_value().explicitly_unveiled; } UnveilAccess permissions() const { return this->metadata_value().permissions; } const String& path() const { return this->metadata_value().full_path; }