diff --git a/Base/usr/share/man/man2/pledge.md b/Base/usr/share/man/man2/pledge.md index e7a289b870d..0304080ea3c 100644 --- a/Base/usr/share/man/man2/pledge.md +++ b/Base/usr/share/man/man2/pledge.md @@ -54,6 +54,7 @@ If the process later attempts to use any system functionality it has previously * `ptrace`: The [`ptrace`(2)](help://man/2/ptrace) syscall (\*) * `prot_exec`: [`mmap`(2)](help://man/2/mmap) and [`mprotect`(2)](help://man/2/mprotect) with `PROT_EXEC` * `map_fixed`: [`mmap`(2)](help://man/2/mmap) with `MAP_FIXED` or `MAP_FIXED_NOREPLACE` (\*) +* `no_error`: Ignore requests of pledge elevation going forwards, this is useful for enforcing _execpromises_ while the child process wants to ask for more upfront (Note that the elevation requests are _not_ granted, merely ignored), this is similar to the `error` pledge in OpenBSD. Promises marked with an asterisk (\*) are SerenityOS specific extensions not supported by the original OpenBSD `pledge()`. diff --git a/Kernel/Process.h b/Kernel/Process.h index 705e5e6d61d..5d19121267d 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -67,7 +67,8 @@ Time kgettimeofday(); __ENUMERATE_PLEDGE_PROMISE(setkeymap) \ __ENUMERATE_PLEDGE_PROMISE(prot_exec) \ __ENUMERATE_PLEDGE_PROMISE(map_fixed) \ - __ENUMERATE_PLEDGE_PROMISE(getkeymap) + __ENUMERATE_PLEDGE_PROMISE(getkeymap) \ + __ENUMERATE_PLEDGE_PROMISE(no_error) enum class Pledge : u32 { #define __ENUMERATE_PLEDGE_PROMISE(x) x, diff --git a/Kernel/Syscalls/pledge.cpp b/Kernel/Syscalls/pledge.cpp index 2ed72afb80e..20c39c81cd6 100644 --- a/Kernel/Syscalls/pledge.cpp +++ b/Kernel/Syscalls/pledge.cpp @@ -46,16 +46,21 @@ ErrorOr Process::sys$pledge(Userspace if (promises) { if (!parse_pledge(promises->view(), new_promises)) return EINVAL; - if (m_protected_values.has_promises && (new_promises & ~m_protected_values.promises)) - return EPERM; + + if (!(m_protected_values.promises & (1u << (u32)Pledge::no_error))) { + if (m_protected_values.has_promises && (new_promises & ~m_protected_values.promises)) + return EPERM; + } } u32 new_execpromises = 0; if (execpromises) { if (!parse_pledge(execpromises->view(), new_execpromises)) return EINVAL; - if (m_protected_values.has_execpromises && (new_execpromises & ~m_protected_values.execpromises)) - return EPERM; + if (!(m_protected_values.promises & (1u << (u32)Pledge::no_error))) { + if (m_protected_values.has_execpromises && (new_execpromises & ~m_protected_values.execpromises)) + return EPERM; + } } // Only apply promises after all validation has occurred, this ensures