diff --git a/zion/capability/capability.h b/zion/capability/capability.h index dc2cbec..1e41fef 100644 --- a/zion/capability/capability.h +++ b/zion/capability/capability.h @@ -20,6 +20,8 @@ class Capability : public RefCounted { template RefPtr obj(); + RefPtr raw_obj() { return obj_; } + uint64_t permissions() { return permissions_; } bool HasPermissions(uint64_t requested) { return (permissions_ & requested) == requested; @@ -37,3 +39,28 @@ RefPtr Capability::obj() { } return StaticCastRefPtr(obj_); } + +template +z_err_t ValidateCapability(const RefPtr& cap, + uint64_t permissions) { + if (!cap) { + return Z_ERR_CAP_NOT_FOUND; + } + + if (cap->raw_obj()->TypeTag() != KernelObjectTag::type) { + return Z_ERR_CAP_TYPE; + } + + if (!cap->HasPermissions(permissions)) { + return Z_ERR_CAP_DENIED; + } + + return Z_OK; +} + +#define RET_IF_NULL(expr) \ + { \ + if (!expr) { \ + return Z_ERR_CAP_TYPE; \ + } \ + } diff --git a/zion/syscall/address_space.cpp b/zion/syscall/address_space.cpp index 4a6ed43..6da3d20 100644 --- a/zion/syscall/address_space.cpp +++ b/zion/syscall/address_space.cpp @@ -1,19 +1,17 @@ #include "syscall/address_space.h" +#include "capability/capability.h" #include "scheduler/scheduler.h" -#include "syscall/syscall.h" z_err_t AddressSpaceMap(ZAddressSpaceMapReq* req) { auto& curr_proc = gScheduler->CurrentProcess(); auto vmas_cap = curr_proc.GetCapability(req->vmas_cap); auto vmmo_cap = curr_proc.GetCapability(req->vmmo_cap); - RET_ERR(ValidateCap(vmas_cap, ZC_WRITE)); - RET_ERR(ValidateCap(vmmo_cap, ZC_WRITE)); + RET_ERR(ValidateCapability(vmas_cap, ZC_WRITE)); + RET_ERR(ValidateCapability(vmmo_cap, ZC_WRITE)); auto vmas = vmas_cap->obj(); auto vmmo = vmmo_cap->obj(); - RET_IF_NULL(vmas); - RET_IF_NULL(vmmo); // FIXME: Validation necessary. if (req->vmas_offset != 0) { diff --git a/zion/syscall/channel.cpp b/zion/syscall/channel.cpp index da54dac..df36ec1 100644 --- a/zion/syscall/channel.cpp +++ b/zion/syscall/channel.cpp @@ -1,7 +1,7 @@ #include "syscall/channel.h" +#include "capability/capability.h" #include "scheduler/scheduler.h" -#include "syscall/syscall.h" z_err_t ChannelCreate(ZChannelCreateReq* req) { auto& proc = gScheduler->CurrentProcess(); @@ -15,19 +15,17 @@ z_err_t ChannelCreate(ZChannelCreateReq* req) { z_err_t ChannelSend(ZChannelSendReq* req) { auto& proc = gScheduler->CurrentProcess(); auto chan_cap = proc.GetCapability(req->chan_cap); - RET_ERR(ValidateCap(chan_cap, ZC_WRITE)); + RET_ERR(ValidateCapability(chan_cap, ZC_WRITE)); auto chan = chan_cap->obj(); - RET_IF_NULL(chan); return chan->Write(req->num_bytes, req->data, req->num_caps, req->caps); } z_err_t ChannelRecv(ZChannelRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); auto chan_cap = proc.GetCapability(req->chan_cap); - RET_ERR(ValidateCap(chan_cap, ZC_READ)); + RET_ERR(ValidateCapability(chan_cap, ZC_READ)); auto chan = chan_cap->obj(); - RET_IF_NULL(chan); return chan->Read(req->num_bytes, req->data, req->num_caps, req->caps); } diff --git a/zion/syscall/port.cpp b/zion/syscall/port.cpp index c3b5472..2d60512 100644 --- a/zion/syscall/port.cpp +++ b/zion/syscall/port.cpp @@ -1,8 +1,8 @@ #include "syscall/port.h" +#include "capability/capability.h" #include "interrupt/interrupt.h" #include "scheduler/scheduler.h" -#include "syscall/syscall.h" z_err_t PortCreate(ZPortCreateReq* req) { auto& proc = gScheduler->CurrentProcess(); @@ -14,20 +14,18 @@ z_err_t PortCreate(ZPortCreateReq* req) { z_err_t PortSend(ZPortSendReq* req) { auto& proc = gScheduler->CurrentProcess(); auto port_cap = proc.GetCapability(req->port_cap); - RET_ERR(ValidateCap(port_cap, ZC_WRITE)); + RET_ERR(ValidateCapability(port_cap, ZC_WRITE)); auto port = port_cap->obj(); - RET_IF_NULL(port); return port->Write(req->num_bytes, req->data, req->num_caps, req->caps); } z_err_t PortRecv(ZPortRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); auto port_cap = proc.GetCapability(req->port_cap); - RET_ERR(ValidateCap(port_cap, ZC_READ)); + RET_ERR(ValidateCapability(port_cap, ZC_READ)); auto port = port_cap->obj(); - RET_IF_NULL(port); ZMessage message{ .num_bytes = *req->num_bytes, .data = const_cast(req->data), @@ -40,10 +38,9 @@ z_err_t PortRecv(ZPortRecvReq* req) { z_err_t PortPoll(ZPortPollReq* req) { auto& proc = gScheduler->CurrentProcess(); auto port_cap = proc.GetCapability(req->port_cap); - RET_ERR(ValidateCap(port_cap, ZC_READ)); + RET_ERR(ValidateCapability(port_cap, ZC_READ)); auto port = port_cap->obj(); - RET_IF_NULL(port); // FIXME: Race condition here where this call could block if the last message // is removed between this check and the port read. if (!port->HasMessages()) { diff --git a/zion/syscall/process.cpp b/zion/syscall/process.cpp index 7f8c90f..5a87fcb 100644 --- a/zion/syscall/process.cpp +++ b/zion/syscall/process.cpp @@ -1,8 +1,8 @@ #include "syscall/process.h" +#include "capability/capability.h" #include "scheduler/process_manager.h" #include "scheduler/scheduler.h" -#include "syscall/syscall.h" z_err_t ProcessExit(ZProcessExitReq* req) { auto curr_thread = gScheduler->CurrentThread(); @@ -16,7 +16,7 @@ z_err_t ProcessExit(ZProcessExitReq* req) { z_err_t ProcessSpawn(ZProcessSpawnReq* req) { auto& curr_proc = gScheduler->CurrentProcess(); auto cap = curr_proc.GetCapability(req->proc_cap); - RET_ERR(ValidateCap(cap, ZC_PROC_SPAWN_PROC)); + RET_ERR(ValidateCapability(cap, ZC_PROC_SPAWN_PROC)); RefPtr proc = Process::Create(); gProcMan->InsertProcess(proc); diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 361f9e2..bc959da 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -43,19 +43,6 @@ void InitSyscall() { SetMSR(LSTAR, reinterpret_cast(syscall_enter)); } -z_err_t ValidateCap(const RefPtr& cap, uint64_t permissions) { - if (!cap) { - return Z_ERR_CAP_NOT_FOUND; - } - // FIXME: Check capability type before permissions, otherwise you can - // get a confusing error. - if (!cap->HasPermissions(permissions)) { - dbgln("PERM, has %x needs %x", cap->permissions(), permissions); - return Z_ERR_CAP_DENIED; - } - return Z_OK; -} - #define CASE(name) \ case kZion##name: \ return name(reinterpret_cast(req)); diff --git a/zion/syscall/syscall.h b/zion/syscall/syscall.h index c6723ff..f34cea6 100644 --- a/zion/syscall/syscall.h +++ b/zion/syscall/syscall.h @@ -4,13 +4,3 @@ #include "include/ztypes.h" void InitSyscall(); - -// FIXME: This probably belongs in capability.h -z_err_t ValidateCap(const RefPtr& cap, uint64_t permissions); - -#define RET_IF_NULL(expr) \ - { \ - if (!expr) { \ - return Z_ERR_CAP_TYPE; \ - } \ - } diff --git a/zion/syscall/thread.cpp b/zion/syscall/thread.cpp index 68a9be1..d6509d5 100644 --- a/zion/syscall/thread.cpp +++ b/zion/syscall/thread.cpp @@ -1,15 +1,14 @@ #include "syscall/thread.h" +#include "capability/capability.h" #include "scheduler/scheduler.h" -#include "syscall/syscall.h" z_err_t ThreadCreate(ZThreadCreateReq* req) { auto& curr_proc = gScheduler->CurrentProcess(); auto cap = curr_proc.GetCapability(req->proc_cap); - RET_ERR(ValidateCap(cap, ZC_PROC_SPAWN_THREAD)); + RET_ERR(ValidateCapability(cap, ZC_PROC_SPAWN_THREAD)); auto parent_proc = cap->obj(); - RET_IF_NULL(parent_proc); auto thread = parent_proc->CreateThread(); *req->thread_cap = curr_proc.AddNewCapability(thread, ZC_WRITE); return Z_OK; @@ -18,10 +17,9 @@ z_err_t ThreadCreate(ZThreadCreateReq* req) { z_err_t ThreadStart(ZThreadStartReq* req) { auto& curr_proc = gScheduler->CurrentProcess(); auto cap = curr_proc.GetCapability(req->thread_cap); - RET_ERR(ValidateCap(cap, ZC_WRITE)); + RET_ERR(ValidateCapability(cap, ZC_WRITE)); auto thread = cap->obj(); - RET_IF_NULL(thread); // FIXME: validate entry point is in user space. thread->Start(req->entry, req->arg1, req->arg2); return Z_OK;