From c19b56dc990eeb808c01b4cefd735322f0f0329f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 12 Apr 2020 20:22:26 +0200 Subject: [PATCH] Kernel+LibC: Add minherit() and MAP_INHERIT_ZERO This patch adds the minherit() syscall originally invented by OpenBSD. Only the MAP_INHERIT_ZERO mode is supported for now. If set on an mmap region, that region will be zeroed out on fork(). --- Kernel/Process.cpp | 26 ++++++++++++++++++++++++++ Kernel/Process.h | 1 + Kernel/Syscall.h | 3 ++- Kernel/UnixTypes.h | 2 ++ Kernel/VM/Region.cpp | 10 ++++++++++ Kernel/VM/Region.h | 8 ++++++++ Libraries/LibC/mman.cpp | 6 ++++++ Libraries/LibC/mman.h | 3 +++ 8 files changed, 58 insertions(+), 1 deletion(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 9b8850793a..b786f92258 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -632,6 +632,32 @@ int Process::sys$madvise(void* address, size_t size, int advice) return -EINVAL; } +int Process::sys$minherit(void* address, size_t size, int inherit) +{ + REQUIRE_PROMISE(stdio); + + auto* region = region_from_range({ VirtualAddress(address), size }); + if (!region) + return -EINVAL; + + if (!region->is_mmap()) + return -EINVAL; + + if (region->is_shared()) + return -EINVAL; + + if (!region->vmobject().is_anonymous()) + return -EINVAL; + + switch (inherit) { + case MAP_INHERIT_ZERO: + region->set_inherit_mode(Region::InheritMode::ZeroedOnFork); + return 0; + } + + return -EINVAL; +} + int Process::sys$purge(int mode) { REQUIRE_NO_PROMISES; diff --git a/Kernel/Process.h b/Kernel/Process.h index 259b164144..708385ac25 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -204,6 +204,7 @@ public: int sys$set_mmap_name(const Syscall::SC_set_mmap_name_params*); int sys$mprotect(void*, size_t, int prot); int sys$madvise(void*, size_t, int advice); + int sys$minherit(void*, size_t, int inherit); int sys$purge(int mode); int sys$select(const Syscall::SC_select_params*); int sys$poll(pollfd*, int nfds, int timeout); diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index d3167bff87..3c2c876e8a 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -182,7 +182,8 @@ namespace Kernel { __ENUMERATE_SYSCALL(perf_event) \ __ENUMERATE_SYSCALL(shutdown) \ __ENUMERATE_SYSCALL(get_stack_bounds) \ - __ENUMERATE_SYSCALL(ptrace) + __ENUMERATE_SYSCALL(ptrace) \ + __ENUMERATE_SYSCALL(minherit) namespace Syscall { diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index d7eab8cf5f..c890befbf7 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -67,6 +67,8 @@ #define MADV_SET_NONVOLATILE 0x200 #define MADV_GET_VOLATILE 0x400 +#define MAP_INHERIT_ZERO 1 + #define F_DUPFD 0 #define F_GETFD 1 #define F_SETFD 2 diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp index 37629baa03..79104439a8 100644 --- a/Kernel/VM/Region.cpp +++ b/Kernel/VM/Region.cpp @@ -68,6 +68,16 @@ NonnullOwnPtr Region::clone() { ASSERT(Process::current); + if (m_inherit_mode == InheritMode::ZeroedOnFork) { + ASSERT(m_mmap); + ASSERT(!m_shared); + ASSERT(vmobject().is_anonymous()); + auto zeroed_region = Region::create_user_accessible(m_range, AnonymousVMObject::create_with_size(size()), 0, m_name, m_access); + zeroed_region->set_mmap(m_mmap); + zeroed_region->set_inherit_mode(m_inherit_mode); + return zeroed_region; + } + if (m_shared) { ASSERT(!m_stack); #ifdef MM_DEBUG diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index 075079c7bd..5671dec795 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -55,6 +55,11 @@ public: Execute = 4, }; + enum class InheritMode { + Default, + ZeroedOnFork, + }; + static NonnullOwnPtr create_user_accessible(const Range&, NonnullRefPtr, size_t offset_in_vmobject, const StringView& name, u8 access, bool cacheable = true); static NonnullOwnPtr create_kernel_only(const Range&, NonnullRefPtr, size_t offset_in_vmobject, const StringView& name, u8 access, bool cacheable = true); @@ -160,6 +165,8 @@ public: // NOTE: These are public so we can make<> them. Region(const Range&, NonnullRefPtr, size_t offset_in_vmobject, const String&, u8 access, bool cacheable); + void set_inherit_mode(InheritMode inherit_mode) { m_inherit_mode = inherit_mode; } + private: Bitmap& ensure_cow_map() const; @@ -183,6 +190,7 @@ private: NonnullRefPtr m_vmobject; String m_name; u8 m_access { 0 }; + InheritMode m_inherit_mode : 3 { InheritMode::Default }; bool m_shared : 1 { false }; bool m_user_accessible : 1 { false }; bool m_cacheable : 1 { false }; diff --git a/Libraries/LibC/mman.cpp b/Libraries/LibC/mman.cpp index d582dc15da..3311c5c53a 100644 --- a/Libraries/LibC/mman.cpp +++ b/Libraries/LibC/mman.cpp @@ -81,4 +81,10 @@ int madvise(void* address, size_t size, int advice) int rc = syscall(SC_madvise, address, size, advice); __RETURN_WITH_ERRNO(rc, rc, -1); } + +int minherit(void* address, size_t size, int inherit) +{ + int rc = syscall(SC_minherit, address, size, inherit); + __RETURN_WITH_ERRNO(rc, rc, -1); +} } diff --git a/Libraries/LibC/mman.h b/Libraries/LibC/mman.h index 0f56dfb5fc..38c3069278 100644 --- a/Libraries/LibC/mman.h +++ b/Libraries/LibC/mman.h @@ -49,6 +49,8 @@ #define MADV_SET_NONVOLATILE 0x200 #define MADV_GET_VOLATILE 0x400 +#define MAP_INHERIT_ZERO 1 + __BEGIN_DECLS void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t); @@ -58,5 +60,6 @@ int munmap(void*, size_t); int mprotect(void*, size_t, int prot); int set_mmap_name(void*, size_t, const char*); int madvise(void*, size_t, int advice); +int minherit(void*, size_t, int inherit); __END_DECLS