Przeglądaj źródła

Kernel: Add a 'no_error' pledge promise

This makes pledge() ignore promises that would otherwise cause it to
fail with EPERM, which is very useful for allowing programs to run under
a "jail" so to speak, without having them termiate early due to a
failing pledge() call.
Ali Mohammad Pur 3 lat temu
rodzic
commit
8233da3398

+ 1 - 0
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()`.
 

+ 2 - 1
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,

+ 9 - 4
Kernel/Syscalls/pledge.cpp

@@ -46,16 +46,21 @@ ErrorOr<FlatPtr> Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*>
     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