Some capability checking progress

This commit is contained in:
Bahadir Balban
2009-10-24 18:44:47 +03:00
parent 4a24e02151
commit 83ce4280b0
11 changed files with 447 additions and 40 deletions

View File

@@ -5,10 +5,8 @@
#include <l4/generic/capability.h>
#include <l4/generic/cap-types.h>
void print_capability(struct capability *cap);
int read_pager_capabilities();
void capability_print(struct capability *cap);
int caps_read_all();
#endif /* __CAPABILITY_H__ */

View File

@@ -1,5 +1,7 @@
/*
* Main function for all tests
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <l4/api/errno.h>
#include <container.h>
@@ -9,7 +11,6 @@
int main(void)
{
printf("%s: Container %s started\n",
__CONTAINER__, __CONTAINER_NAME__);

View File

@@ -1,11 +1,80 @@
/*
* Capability-related userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <capability.h>
#include <stdio.h>
#include <l4lib/arch/syscalls.h>
static struct capability cap_array[30];
static int total_caps;
void print_capability(struct capability *cap)
struct cap_group {
struct cap_list virtmem;
struct cap_list physmem;
struct cap_list threadpool;
struct cap_list tctrl;
struct cap_list exregs;
struct cap_list ipc;
struct cap_list mutex;
struct cap_list sched;
struct cap_list mutexpool;
struct cap_list spacepool;
struct cap_list cappool;
};
static inline struct capability *cap_get_thread()
{
}
static inline struct capability *cap_get_space()
{
}
static inline struct capability *cap_get_ipc()
{
}
static inline struct capability *cap_get_virtmem()
{
}
static inline struct capability *cap_get_physmem()
{
}
static inline struct capability *cap_get_physmem(unsigned long phys)
{
}
static inline struct capability *cap_get_virtmem(unsigned long virt)
{
}
static inline struct capability *cap_get_byid(l4id_t id)
{
}
void cap_share_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags)
{
}
void cap_grant_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags)
{
}
void cap_print(struct capability *cap)
{
printf("Capability id:\t\t\t%d\n", cap->capid);
printf("Capability resource id:\t\t%d\n", cap->resid);
@@ -82,7 +151,7 @@ void print_capability(struct capability *cap)
printf("\n");
}
int read_pager_capabilities()
int cap_read_all(void)
{
int ncaps;
int err;
@@ -95,7 +164,6 @@ int read_pager_capabilities()
"complete CAP_CONTROL_NCAPS request.\n");
BUG();
}
total_caps = ncaps;
/* Read all capabilities */
if ((err = l4_capability_control(CAP_CONTROL_READ,
@@ -106,8 +174,8 @@ int read_pager_capabilities()
BUG();
}
for (int i = 0; i < total_caps; i++)
print_capability(&cap_array[i]);
for (int i = 0; i < ncaps; i++)
cap_print(&cap_array[i]);
return 0;
}

View File

@@ -79,7 +79,7 @@ int capability_test(void)
int TEST_MUST_SUCCEED = 1;
/* Read pager capabilities */
read_pager_capabilities();
caps_read_all();
/*
* Create new thread that will attempt

View File

@@ -37,6 +37,7 @@
#define CAP_RTYPE_MUTEXPOOL (1 << 26)
#define CAP_RTYPE_MAPPOOL (1 << 27) /* For pmd spending */
#define CAP_RTYPE_CAPPOOL (1 << 28) /* For new cap generation */
#define CAP_RTYPE_PGGROUP (1 << 29) /* Group of paged threads */
#define cap_rtype(c) ((c)->type & CAP_RTYPE_MASK)

View File

@@ -3,7 +3,7 @@ Import('env')
Import('symbols')
# The set of source files associated with this SConscript file.
src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'map.c', 'mutex.c', 'capability.c', 'exregs.c']
src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'map.c', 'mutex.c', 'cap.c', 'exregs.c']
obj = env.Object(src_local)

View File

@@ -576,6 +576,10 @@ int sys_ipc(l4id_t to, l4id_t from, unsigned int flags)
goto error;
}
/* Everything in place, now check capability */
if ((err = cap_ipc_check(to, from, flags, ipc_type)) < 0)
return -ENOCAP;
/* Encode ipc type in task flags */
tcb_set_ipc_flags(current, flags);

View File

@@ -10,22 +10,17 @@
#include <l4/api/space.h>
int sys_map(unsigned long phys, unsigned long virt, unsigned long npages,
unsigned long flags, unsigned int tid)
unsigned int flags, l4id_t tid)
{
struct ktcb *target;
int err;
if (tid == current->tid) { /* The easiest case */
target = current;
goto found;
} else /* else search the tcb from its hash list */
if ((target = tcb_find(tid)))
goto found;
if ((err = cap_map_check(phys, virt, npages, flags, tid)) < 0)
return err;
BUG();
return -EINVAL;
if (!(target = tcb_find(tid)))
return -ESRCH;
found:
// printk("%s (%d) Mapping from 0x%lx to 0x%lxp, %lu pages\n", __FUNCTION__, tid, phys, virt, npages);
add_mapping_pgd(phys, virt, npages << PAGE_BITS, flags, TASK_PGD(target));
return 0;

View File

@@ -464,6 +464,9 @@ int sys_thread_control(unsigned int flags, struct task_ids *ids)
MAP_USR_RW_FLAGS, 1)) < 0)
return err;
if ((err = cap_thread_check(flags, ids)) < 0)
return err;
switch (flags & THREAD_ACTION_MASK) {
case THREAD_CREATE:
ret = thread_create(ids, flags);

View File

@@ -93,22 +93,6 @@ struct capability *capability_find_by_rtype(struct ktcb *task,
if (cap_rtype(cap) == rtype)
return cap;
/* Find group leader */
BUG_ON(!(tgleader = tcb_find(task->tgid)));
/* Search thread group list */
list_foreach_struct(cap, &tgleader->tgroup_cap_list.caps, list)
if (cap_rtype(cap) == rtype)
return cap;
/* Find pager */
BUG_ON(!(pager = tcb_find(task->pagerid)));
/* Search pager's paged-children capability list */
list_foreach_struct(cap, &pager->pager_cap_list.caps, list)
if (cap_rtype(cap) == rtype)
return cap;
/* Search container list */
list_foreach_struct(cap, &task->container->cap_list.caps, list)
if (cap_rtype(cap) == rtype)
@@ -117,6 +101,359 @@ struct capability *capability_find_by_rtype(struct ktcb *task,
return 0;
}
typedef struct capability *(cap_match_func *)
(struct capability *cap, void *match_args)
cap_match_func_t;
struct capability *cap_find(struct ktcb *task, cap_match_func_t cap_match_func,
void *match_args, unsigned int val)
{
struct capability *cap;
struct ktcb *tgleader, *pager;
/* Search task's own list */
list_foreach_struct(cap, &task->cap_list.caps, list)
if ((cap = cap_match_func(cap, match_args, val)))
return cap;
/* Search space list */
list_foreach_struct(cap, &task->space->cap_list.caps, list)
if ((cap = cap_match_func(cap, match_args, val)))
return cap;
/* Search container list */
list_foreach_struct(cap, &task->container->cap_list.caps, list)
if ((cap = cap_match_func(cap, match_args, val)))
return cap;
return 0;
}
struct capability *
cap_match_mem(struct capability *cap,
void *match_args, unsigned int valid)
{
struct capability *match = match_args;
/* Equality-check these fields based on valid vector */
if (valid & FIELD_TO_BIT(struct capability, capid))
if (cap->capid != match->capid)
return 0;
if (valid & FIELD_TO_BIT(struct capability, resid))
if (cap->resid != match->resid)
return 0;
if (valid & FIELD_TO_BIT(struct capability, owner))
if (cap->owner != match->owner)
return 0;
if (valid & FIELD_TO_BIT(struct capability, type))
if (cap->type != match->type)
return 0;
if (valid & FIELD_TO_BIT(struct capability, access))
if ((cap->access & match->access)
!= match->access)
return 0;
/* Checked these together as a range */
if (valid & FIELD_TO_BIT(struct capability, start) ||
valid & FIELD_TO_BIT(struct capability, end))
if (!(match->start >= cap->start &&
match->end <= cap->end &&
match->start < match->end))
return 0;
/* It is a match */
return cap;
}
struct ipc_match = {
l4id_t tid;
l4id_t tgid;
l4id_t spid;
l4id_t cid;
struct capability *cap;
};
/*
* In an ipc, we could look for access bits, resource type and target id
*/
struct capability *
cap_match_ipc(struct capability *cap, void *match_args, unsigned int valid)
{
struct ipc_match *ipc_match = match_args;
struct capability *cap = ipc_match->cap;
/*
* Check these for basic equality.
*/
if (valid & FIELD_TO_BIT(struct capability, capid))
if (cap->capid != match->capid)
return 0;
if (valid & FIELD_TO_BIT(struct capability, owner))
if (cap->owner != match->owner)
return 0;
if (valid & FIELD_TO_BIT(struct capability, access))
if ((cap->access & match->access)
!= match->access)
return 0;
/*
* Check these optimised/specially.
* rtype and target are checked against each
* other all at once
*/
if (valid & FIELD_TO_BIT(struct capability, resid)) {
switch (cap_rtype(cap)) {
case CAP_RTYPE_THREAD:
if (ipc_matcher->tid != resid)
return 0;
break;
case CAP_RTYPE_TGROUP:
if (ipc_matcher->tgid != resid)
return 0;
break;
case CAP_RTYPE_SPACE:
if (ipc_matcher->spid != resid)
return 0;
break;
case CAP_RTYPE_CONTAINER:
if (ipc_matcher->cid != resid)
return 0;
break;
/*
* It's simply a bug to
* get an unknown resource here
*/
default:
BUG();
}
}
return cap;
}
int cap_ipc_check(struct ktcb *target, l4id_t from,
unsigned int flags, unsigned int ipc_type)
{
unsigned int valid = 0;
struct capability ipccap = {
.access = ipc_flags_type_to_access(flags, ipc_type);
};
/*
* All these ids will get checked at once,
* depending on the encountered capability's
* rtype field
*/
struct ipc_matcher ipc_matcher = {
.tid = target->tid,
.tgid = target->tgid,
.spid = target->space->spid,
.cid = target->container->cid,
.ipccap = ipccap,
};
valid |= FIELD_TO_BIT(struct capability, access);
valid |= FIELD_TO_BIT(struct capability, resid);
if (!(cap_find(task, cap_match_ipc,
&ipc_matcher, valid)))
return -ENOCAP;
return 0;
}
struct exregs_match = {
l4id_t tid
l4id_t pagerid;
l4id_t tgid;
l4id_t spid;
l4id_t cid;
struct capability *cap;
};
struct capability *
cap_match_thread(struct capability *cap, void *match_args, unsigned int valid)
{
struct thread_match *match = match_args;
struct capability *cap = match->cap;
/*
* Check these for basic equality.
*/
if (valid & FIELD_TO_BIT(struct capability, capid))
if (cap->capid != match->capid)
return 0;
if (valid & FIELD_TO_BIT(struct capability, owner))
if (cap->owner != match->owner)
return 0;
if (valid & FIELD_TO_BIT(struct capability, access))
if ((cap->access & match->access)
!= match->access)
return 0;
/*
* Check these optimised/specially.
* rtype and target are checked against each
* other all at once
*/
if (valid & FIELD_TO_BIT(struct capability, resid)) {
switch (cap_rtype(cap)) {
/* Ability to thread_control over a paged group */
case CAP_RTYPE_PGGROUP:
if (match->pagerid != resid)
return 0;
break;
case CAP_RTYPE_TGROUP:
if (match->tgid != resid)
return 0;
break;
case CAP_RTYPE_SPACE:
if (match->spid != resid)
return 0;
break;
case CAP_RTYPE_CONTAINER:
if (match->cid != resid)
return 0;
break;
/*
* It's simply a bug to
* get an unknown resource here
*/
default:
BUG();
}
}
return cap;
}
/*
* TODO: We are here!!!
*/
int cap_exregs_check(unsigned int flags, struct task_ids *ids)
{
struct capability cap = {
.access = thread_control_flags_to_access(flags);
/* all resid's checked all at once by comparing against rtype */
};
struct thread_match match = {
.pagerid = current->tid
.tgid = current->tgid,
.spid = current->spid,
.cid = current->cid,
.cap = threadmatch,
};
unsigned int valid = 0;
valid |= FIELD_TO_BIT(struct capability, access);
valid |= FIELD_TO_BIT(struct capability, resid);
if (!(cap_find(task, cap_match_thread,
&thread_match, valid)))
return -ENOCAP;
return 0;
}
/*
* FIXME: As new pagers, thread groups,
* thread ids, spaces are created, we need to
* give them thread_control capabilities dynamically,
* based on those ids!!! How do we get to do that, so that
* in userspace it looks not so difficult ???
*/
struct thread_match = {
l4id_t tgid;
l4id_t tid;
l4id_t pagerid;
l4id_t spid;
l4id_t cid;
unsigned int thread_control_flags;
};
def thread_create():
new_space, same_tgid, same_pager,
check_existing_ids(tid, same_tgid, same_pager, thread_create)
thread_create(new_space)
thread_add_cap(new_space, all other caps)
/*
* What do you match here?
*
* THREAD_CREATE:
* - TC_SAME_SPACE
* - spid -> Does thread have cap to create in that space?
* - cid -> Does thread have cap to create in that container?
* - tgid -> Does thread have cap to create in that thread group?
* - pagerid -> Does thread have cap to create in that group of paged threads?
* - TC_NEW_SPACE or TC_COPY_SPACE
* - Check cid, tgid, pagerid,
* - TC_SHARE_GROUP
* - Check tgid
* - TC_AS_PAGER
* - pagerid -> Does thread have cap to create in that group of paged threads?
* - TC_SHARE_PAGER
* - pagerid -> Does thread have cap to create in that group of paged threads?
* New group -> New set of caps, thread_control, exregs, ipc, ... all of them!
* New pager -> New set of caps for that pager.
* New thread -> New set of caps for that thread!
* New space -> New set of caps for that space! So many capabilities!
*/
itn cap_thread_check(struct ktcb *task, unsigned int flags, struct task_ids *ids)
{
struct thread_matcher = {
.pagerid = current->tid
.tgid = current->tgid,
.spid = current->spid,
.cid = current->cid,
.thread_control_flags = flags;
};
unsigned int valid = 0;
valid |= FIELD_TO_BIT(struct capability, access);
valid |= FIELD_TO_BIT(struct capability, resid);
if (!(cap_find(task, cap_match_thread,
&thread_matcher, valid)))
return -ENOCAP;
return 0;
}
int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt,
unsigned long npages, unsigned int flags, l4id_t tid)
{
struct capability *physmem, *virtmem;
struct capability physmatch = {
.start = __pfn(phys),
.end = __pfn(phys) + npages,
.type = CAP_TYPE_PHYSMEM,
.flags = map_flags_to_cap_flags(flags),
}
struct capability virtmatch = {
.start = __pfn(virt),
.end = __pfn(virt) + npages,
.type = CAP_TYPE_VIRTMEM,
.flags = map_flags_to_cap_flags(flags),
}
unsigned int virt_valid = 0;
unsigned int phys_valid = 0;
virt_valid |= FIELD_TO_BIT(struct capability, access);
virt_valid |= FIELD_TO_BIT(struct capability, start);
virt_valid |= FIELD_TO_BIT(struct capability, end);
phys_valid |= FIELD_TO_BIT(struct capability, access);
phys_valid |= FIELD_TO_BIT(struct capability, start);
phys_valid |= FIELD_TO_BIT(struct capability, end);
if (!(physmem = cap_find(task, cap_match_mem,
&physmatch, phys_valid)))
return -ENOCAP;
if (!(virtmem = cap_find(task, cap_match_mem,
&virtmatch, virt_valid)))
return -ENOCAP;
return 0;
}
/*
* FIXME:
*