mirror of
https://github.com/drasko/codezero.git
synced 2026-01-13 03:13:15 +01:00
Some capability checking progress
This commit is contained in:
192
src/api/cap.c
Normal file
192
src/api/cap.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Capability manipulation syscall.
|
||||
*
|
||||
* The heart of Codezero security
|
||||
* mechanisms lay here.
|
||||
*
|
||||
* Copyright (C) 2009 Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <l4/api/capability.h>
|
||||
#include <l4/generic/capability.h>
|
||||
#include <l4/generic/container.h>
|
||||
#include <l4/generic/tcb.h>
|
||||
#include <l4/api/errno.h>
|
||||
#include INC_API(syscall.h)
|
||||
|
||||
int read_task_capabilities(void *userbuf)
|
||||
{
|
||||
int copy_size, copy_offset = 0;
|
||||
struct capability *cap;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Currently only pagers can
|
||||
* read their own capabilities
|
||||
*/
|
||||
if (current != current->pager->tcb)
|
||||
return -EPERM;
|
||||
|
||||
/* Determine size of pager capabilities */
|
||||
copy_size = current->cap_list.ncaps * sizeof(*cap);
|
||||
|
||||
/* Validate user buffer for this copy size */
|
||||
if ((err = check_access((unsigned long)userbuf,
|
||||
copy_size,
|
||||
MAP_USR_RW_FLAGS, 1)) < 0)
|
||||
return err;
|
||||
|
||||
/* Copy capabilities from list to buffer */
|
||||
list_foreach_struct(cap, ¤t->cap_list.caps,
|
||||
list) {
|
||||
memcpy(userbuf + copy_offset,
|
||||
cap, sizeof(*cap));
|
||||
copy_offset += sizeof(*cap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently shares _all_ capabilities of a task with a
|
||||
* collection of threads
|
||||
*
|
||||
* FIXME: Check ownership for sharing.
|
||||
*
|
||||
* Currently we don't need to check since we _only_ share
|
||||
* the ones from our own private list. If we shared from
|
||||
* a collection's list, we would need to check ownership.
|
||||
*/
|
||||
int capability_share(unsigned int share_flags)
|
||||
{
|
||||
switch (share_flags) {
|
||||
case CAP_SHARE_SPACE:
|
||||
cap_list_move(¤t->space->cap_list,
|
||||
¤t->cap_list);
|
||||
break;
|
||||
case CAP_SHARE_CONTAINER:
|
||||
cap_list_move(&curcont->cap_list,
|
||||
¤t->cap_list);
|
||||
break;
|
||||
case CAP_SHARE_CHILD:
|
||||
/*
|
||||
* Move own capabilities to paged-children
|
||||
* cap list so that all children can benefit
|
||||
* from our own capabilities.
|
||||
*/
|
||||
cap_list_move(¤t->pager_cap_list,
|
||||
¤t->cap_list);
|
||||
break;
|
||||
case CAP_SHARE_SIBLING: {
|
||||
/* Find our pager */
|
||||
struct ktcb *pager = tcb_find(current->pagerid);
|
||||
|
||||
/*
|
||||
* Add own capabilities to its
|
||||
* paged-children cap_list
|
||||
*/
|
||||
cap_list_move(&pager->pager_cap_list,
|
||||
¤t->cap_list);
|
||||
break;
|
||||
}
|
||||
case CAP_SHARE_GROUP: {
|
||||
struct ktcb *tgroup_leader;
|
||||
|
||||
BUG_ON(!(tgroup_leader = tcb_find(current->tgid)));
|
||||
cap_list_move(&tgroup_leader->tgroup_cap_list,
|
||||
¤t->cap_list);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read, manipulate capabilities. Currently only capability read support.
|
||||
*/
|
||||
int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch(req) {
|
||||
/* Return number of capabilities the thread has */
|
||||
case CAP_CONTROL_NCAPS:
|
||||
if (current != current->pager->tcb)
|
||||
return -EPERM;
|
||||
|
||||
if ((err = check_access((unsigned long)userbuf,
|
||||
sizeof(int),
|
||||
MAP_USR_RW_FLAGS, 1)) < 0)
|
||||
return err;
|
||||
|
||||
/* Copy ncaps value */
|
||||
*((int *)userbuf) = current->cap_list.ncaps;
|
||||
break;
|
||||
|
||||
/* Return all capabilities as an array of capabilities */
|
||||
case CAP_CONTROL_READ:
|
||||
err = read_task_capabilities(userbuf);
|
||||
break;
|
||||
case CAP_CONTROL_SHARE:
|
||||
err = capability_share(flags);
|
||||
break;
|
||||
default:
|
||||
/* Invalid request id */
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
int capability_grant(struct ktcb *recv, struct ktcb *send, struct capability *cap)
|
||||
{
|
||||
list_del(&cap->list);
|
||||
list_add(&cap->list, &recv->cap_list);
|
||||
}
|
||||
|
||||
struct cap_split_desc {
|
||||
unsigned int valid;
|
||||
unsigned int access;
|
||||
unsigned long size;
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
};
|
||||
|
||||
struct capability *capability_diff(struct capability *cap, struct cap_split_desc *split)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int capability_split(struct ktcb *recv, struct ktcb *send, struct capability *cap, struct cap_split_desc *split)
|
||||
{
|
||||
capability_diff(orig, new, split);
|
||||
}
|
||||
|
||||
int capability_split(struct capability *orig, struct capability *diff, unsigned int valid)
|
||||
{
|
||||
struct capability *new;
|
||||
|
||||
if (!(new = alloc_capability()))
|
||||
return -ENOMEM;
|
||||
|
||||
if (valid & FIELD_TO_BIT(struct capability, access)) {
|
||||
new->access = orig->access & diff->access;
|
||||
orig->access &= ~diff->access;
|
||||
}
|
||||
if (valid & FIELD_TO_BIT(struct capability, size)) {
|
||||
new->size = orig->size - diff->size;
|
||||
orig->size -= diff->size;
|
||||
}
|
||||
if (valid & FIELD_TO_BIT(struct capability, start)) {
|
||||
/* This gets complicated, may return -ENOSYS for now */
|
||||
memcap_unmap(cap, diff->start, diff->end);
|
||||
new->size = orig->size - split->size;
|
||||
orig->size -= split->size;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user