#include "Pledge.h" #include "Log.h" #include "memory/MemoryManager.h" static const char* promise_names[] = { #define __enumerate(promise) #promise, enumerate_promises(__enumerate) #undef __enumerate }; Result check_pledge(Thread* thread, Promise promise) { // Thread has not called pledge(). if (thread->promises < 0) return {}; int mask = (1 << (int)promise); if ((thread->promises & mask) != mask) { kerrorln("Pledge violation in thread %d! Has not pledged %s", thread->id, promise_names[(int)promise]); if (thread->promises & (1 << (int)Promise::p_error)) return err(ENOSYS); // Kill this thread with an uncatchable SIGABRT. For this, we reset the disposition of SIGABRT to the default // (dump core). We could just kill the thread here and be done, but that discards anything on the current stack, // which means that some destructors might not be called. Instead, leave the job to the next call of // Thread::process_pending_signals(). thread->signal_handlers[SIGABRT - 1].sa_handler = SIG_DFL; // If there are any other pending signals, they might be processed before SIGABRT. Avoid that by resetting the // thread's pending signals. thread->pending_signals = 0; thread->send_signal(SIGABRT); // This should never arrive to userspace. return err(ENOSYS); } return {}; } Result parse_promises(u64 pledge) { if (!pledge) return -1; auto text = TRY(MemoryManager::strdup_from_user(pledge)); if (text.is_empty()) return 0; auto promises = TRY(text.split(" ")); int result = 0; for (const auto& promise : promises) { for (int i = 0; i < (int)Promise::num_promises; i++) { if (promise.view() == promise_names[i]) { result |= (1 << i); goto found; } } return err(EINVAL); found: continue; } return result; }