[zion] Move capability validation to capability.h

This commit is contained in:
Drew Galbraith 2023-06-20 15:50:49 -07:00
parent 93cf8f2740
commit 172bf51db7
8 changed files with 42 additions and 47 deletions

View File

@ -20,6 +20,8 @@ class Capability : public RefCounted<Capability> {
template <typename T>
RefPtr<T> obj();
RefPtr<KernelObject> raw_obj() { return obj_; }
uint64_t permissions() { return permissions_; }
bool HasPermissions(uint64_t requested) {
return (permissions_ & requested) == requested;
@ -37,3 +39,28 @@ RefPtr<T> Capability::obj() {
}
return StaticCastRefPtr<T>(obj_);
}
template <typename T>
z_err_t ValidateCapability(const RefPtr<Capability>& cap,
uint64_t permissions) {
if (!cap) {
return Z_ERR_CAP_NOT_FOUND;
}
if (cap->raw_obj()->TypeTag() != KernelObjectTag<T>::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; \
} \
}

View File

@ -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<AddressSpace>(vmas_cap, ZC_WRITE));
RET_ERR(ValidateCapability<MemoryObject>(vmmo_cap, ZC_WRITE));
auto vmas = vmas_cap->obj<AddressSpace>();
auto vmmo = vmmo_cap->obj<MemoryObject>();
RET_IF_NULL(vmas);
RET_IF_NULL(vmmo);
// FIXME: Validation necessary.
if (req->vmas_offset != 0) {

View File

@ -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<Channel>(chan_cap, ZC_WRITE));
auto chan = chan_cap->obj<Channel>();
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<Channel>(chan_cap, ZC_READ));
auto chan = chan_cap->obj<Channel>();
RET_IF_NULL(chan);
return chan->Read(req->num_bytes, req->data, req->num_caps, req->caps);
}

View File

@ -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>(port_cap, ZC_WRITE));
auto port = port_cap->obj<Port>();
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>(port_cap, ZC_READ));
auto port = port_cap->obj<Port>();
RET_IF_NULL(port);
ZMessage message{
.num_bytes = *req->num_bytes,
.data = const_cast<void*>(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>(port_cap, ZC_READ));
auto port = port_cap->obj<Port>();
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()) {

View File

@ -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<Process>(cap, ZC_PROC_SPAWN_PROC));
RefPtr<Process> proc = Process::Create();
gProcMan->InsertProcess(proc);

View File

@ -43,19 +43,6 @@ void InitSyscall() {
SetMSR(LSTAR, reinterpret_cast<uint64_t>(syscall_enter));
}
z_err_t ValidateCap(const RefPtr<Capability>& 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<Z##name##Req*>(req));

View File

@ -4,13 +4,3 @@
#include "include/ztypes.h"
void InitSyscall();
// FIXME: This probably belongs in capability.h
z_err_t ValidateCap(const RefPtr<Capability>& cap, uint64_t permissions);
#define RET_IF_NULL(expr) \
{ \
if (!expr) { \
return Z_ERR_CAP_TYPE; \
} \
}

View File

@ -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<Process>(cap, ZC_PROC_SPAWN_THREAD));
auto parent_proc = cap->obj<Process>();
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<Thread>(cap, ZC_WRITE));
auto thread = cap->obj<Thread>();
RET_IF_NULL(thread);
// FIXME: validate entry point is in user space.
thread->Start(req->entry, req->arg1, req->arg2);
return Z_OK;