Capability-enabled kernel running 2_posix test OK.

This commit is contained in:
Bahadir Balban
2009-10-27 15:59:07 +02:00
parent d1f25763ac
commit 5840d6d696
12 changed files with 244 additions and 154 deletions

View File

@@ -39,6 +39,7 @@ containers_menu 'Container Setup'
arch_type 'Main architecture'
CONTAINERS 'Number of containers'
CAPABILITIES 'Enable capability checking'
#############
# CHOICES #
@@ -97,9 +98,11 @@ menu main_menu
CONTAINERS%
containers_menu
#############
#############`
# RULES #
#############
#Capability rules:
default CAPABILITIES from y
#Platform rules:
unless SUBARCH_V5 suppress PLATFORM_PB926

View File

@@ -210,7 +210,7 @@ int read_pager_capabilities()
/* Share all of them with paged children */
if ((err = l4_capability_control(CAP_CONTROL_SHARE,
CAP_SHARE_CHILD,
CAP_SHARE_CONTAINER,
0)) < 0) {
printf("l4_capability_control() sharing of "
"capabilities failed.\n Could not "

View File

@@ -9,6 +9,7 @@
static struct capability cap_array[30];
#if 0
struct cap_group {
struct cap_list virtmem;
struct cap_list physmem;
@@ -73,6 +74,7 @@ void cap_grant_single(struct capability *orig, struct capability *share, l4id_t
{
}
#endif
void cap_print(struct capability *cap)
{
@@ -151,7 +153,7 @@ void cap_print(struct capability *cap)
printf("\n");
}
int cap_read_all(void)
int caps_read_all(void)
{
int ncaps;
int err;

View File

@@ -1,4 +1,5 @@
#if 0
int mutex_user_thread(void *arg)
{
@@ -215,5 +216,5 @@ out_err:
#endif

View File

@@ -5,9 +5,9 @@
#define THREAD_CREATE 0x0000
#define THREAD_RUN 0x0001
#define THREAD_SUSPEND 0x0002
#define THREAD_RESUME 0x0003
#define THREAD_DESTROY 0x0004
#define THREAD_RECYCLE 0x0005
#define THREAD_DESTROY 0x0003
#define THREAD_RECYCLE 0x0004
#define THREAD_WAIT 0x0005
#define THREAD_CREATE_MASK 0x0FF0
#define TC_SHARE_CAPS 0x0010 /* Share all thread capabilities */

View File

@@ -28,7 +28,7 @@
#define CAP_RTYPE_TGROUP (1 << 17)
#define CAP_RTYPE_SPACE (1 << 18)
#define CAP_RTYPE_CONTAINER (1 << 19)
#define CAP_RTYPE_UMUTEX (1 << 20) /* Don't mix with pool version */
#define CAP_RTYPE_PGGROUP (1 << 20) /* Group of paged threads */
#define CAP_RTYPE_VIRTMEM (1 << 21)
#define CAP_RTYPE_PHYSMEM (1 << 22)
#define CAP_RTYPE_CPUPOOL (1 << 23)
@@ -37,7 +37,6 @@
#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)
@@ -48,9 +47,10 @@
/* Thread control capability */
#define CAP_TCTRL_CREATE (1 << 0)
#define CAP_TCTRL_DESTROY (1 << 1)
#define CAP_TCTRL_SUSPEND (1 << 2)
#define CAP_TCTRL_RESUME (1 << 3)
#define CAP_TCTRL_RUN (1 << 2)
#define CAP_TCTRL_SUSPEND (1 << 3)
#define CAP_TCTRL_RECYCLE (1 << 4)
#define CAP_TCTRL_WAIT (1 << 5)
/* Exchange registers capability */
#define CAP_EXREGS_RW_PAGER (1 << 0)

View File

@@ -142,7 +142,7 @@ struct capability *cap_list_find_by_rtype(struct cap_list *clist,
/* Capability checking on system calls */
int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt,
unsigned long npages, unsigned int flags, l4id_t tid);
unsigned long npages, unsigned int flags);
int cap_thread_check(struct ktcb *task, unsigned int flags,
struct task_ids *ids);
int cap_exregs_check(struct ktcb *task, struct exregs_data *exregs);

View File

@@ -19,6 +19,7 @@ from config.configuration import *
containers_menu = \
'''
menu containers_menu
CAPABILITIES
'''
containers_constraint = \

View File

@@ -109,7 +109,7 @@ cap_all_others = \
\t\t\t[%d] = {
\t\t\t\t.type = CAP_TYPE_TCTRL | CAP_RTYPE_CONTAINER,
\t\t\t\t.access = CAP_TCTRL_CREATE | CAP_TCTRL_DESTROY
\t\t\t\t | CAP_TCTRL_SUSPEND | CAP_TCTRL_RESUME
\t\t\t\t | CAP_TCTRL_SUSPEND | CAP_TCTRL_RUN
\t\t\t\t | CAP_TCTRL_RECYCLE,
\t\t\t\t.start = 0, .end = 0, .size = 0,
\t\t\t},
@@ -121,6 +121,17 @@ cap_all_others = \
\t\t\t\t.start = 0, .end = 0, .size = 0,
\t\t\t},
\t\t\t[%d] = {
\t\t\t\t.type = CAP_TYPE_CAP | CAP_RTYPE_CONTAINER,
\t\t\t\t.access = CAP_CAP_MODIFY | CAP_CAP_GRANT
\t\t\t\t| CAP_CAP_READ | CAP_CAP_SHARE,
\t\t\t\t.start = 0, .end = 0, .size = 0,
\t\t\t},
\t\t\t[%d] = {
\t\t\t\t.type = CAP_TYPE_UMUTEX | CAP_RTYPE_CONTAINER,
\t\t\t\t.access = CAP_UMUTEX_LOCK | CAP_UMUTEX_UNLOCK,
\t\t\t\t.start = 0, .end = 0, .size = 0,
\t\t\t},
\t\t\t[%d] = {
\t\t\t\t.type = CAP_TYPE_QUANTITY
\t\t\t\t | CAP_RTYPE_THREADPOOL,
\t\t\t\t.access = 0, .start = 0, .end = 0,
@@ -203,7 +214,7 @@ def generate_kernel_cinfo(config, cinfo_path):
with open(cinfo_path, 'w+') as cinfo_file:
fbody = cinfo_file_start % pager_ifdefs
total_other_caps = 9
total_other_caps = 11
for c in containers:
# Currently only these are considered as capabilities
total_caps = c.virt_regions + c.phys_regions + total_other_caps
@@ -216,7 +227,7 @@ def generate_kernel_cinfo(config, cinfo_path):
for mem_index in range(c.phys_regions):
fbody += cap_physmem % { 'capidx' : cap_index, 'cn' : c.id, 'pn' : mem_index }
cap_index += 1
fbody += cap_all_others % (tuple(range(cap_index, total_caps)))
fbody += cap_all_others % tuple(range(cap_index, total_caps))
fbody += pager_end
fbody += cinfo_end
fbody += cinfo_file_end

View File

@@ -18,7 +18,7 @@ int sys_map(unsigned long phys, unsigned long virt, unsigned long npages,
if (!(target = tcb_find(tid)))
return -ESRCH;
if ((err = cap_map_check(target, phys, virt, npages, flags, tid)) < 0)
if ((err = cap_map_check(target, phys, virt, npages, flags)) < 0)
return err;
add_mapping_pgd(phys, virt, npages << PAGE_BITS, flags, TASK_PGD(target));

View File

@@ -203,20 +203,6 @@ void thread_destroy_current(void)
sched_suspend_sync();
}
int thread_resume(struct ktcb *task)
{
if (!mutex_trylock(&task->thread_control_lock))
return -EAGAIN;
/* Put task into runqueue as runnable */
sched_resume_async(task);
/* Release lock and return */
mutex_unlock(&task->thread_control_lock);
return 0;
}
/* Runs a thread for the first time */
int thread_start(struct ktcb *task)
{
@@ -443,9 +429,6 @@ int sys_thread_control(unsigned int flags, struct task_ids *ids)
case THREAD_SUSPEND:
ret = thread_suspend(task, flags);
break;
case THREAD_RESUME:
ret = thread_resume(task);
break;
case THREAD_DESTROY:
ret = thread_destroy(task);
break;

View File

@@ -9,6 +9,7 @@
#include <l4/generic/cap-types.h>
#include <l4/generic/tcb.h>
#include <l4/api/capability.h>
#include <l4/api/thread.h>
#include <l4/api/errno.h>
#include <l4/lib/printk.h>
#include <l4/api/thread.h>
@@ -44,6 +45,7 @@ struct capability *capability_create(void)
return cap;
}
#if defined(CONFIG_CAPABILITIES)
int capability_consume(struct capability *cap, int quantity)
{
if (cap->size < cap->used + quantity)
@@ -60,6 +62,18 @@ int capability_free(struct capability *cap, int quantity)
return 0;
}
#else
int capability_consume(struct capability *cap, int quantity)
{
return 0;
}
int capability_free(struct capability *cap, int quantity)
{
return 0;
}
#endif
struct capability *cap_list_find_by_rtype(struct cap_list *cap_list,
unsigned int rtype)
{
@@ -77,10 +91,12 @@ struct capability *cap_list_find_by_rtype(struct cap_list *cap_list,
* Search all capability lists that task is allowed.
*
* FIXME:
* Tasks won't always search for a capability randomly. Consider
* Tasks should not always search for a capability randomly. Consider
* mutexes, if a mutex is freed, it needs to be accounted to private
* pool first if that is not full, because freeing it into shared
* pool may lose the mutex right to another task.
* pool may lose the mutex right to another task. In other words,
* when you're freeing a mutex, we should know which capability pool
* to free it to.
*
* In conclusion freeing of pool-type capabilities need to be done
* in order of privacy. -> It may get confusing as a space, thread
@@ -116,25 +132,25 @@ typedef struct capability *(*cap_match_func_t) \
struct capability *cap_find(struct ktcb *task, cap_match_func_t cap_match_func,
void *match_args, unsigned int cap_type)
{
struct capability *cap;
struct capability *cap, *found;
/* Search task's own list */
list_foreach_struct(cap, &task->cap_list.caps, list)
if (cap_type(cap) == cap_type &&
((cap = cap_match_func(cap, match_args))))
return cap;
((found = cap_match_func(cap, match_args))))
return found;
/* Search space list */
list_foreach_struct(cap, &task->space->cap_list.caps, list)
if (cap_type(cap) == cap_type &&
((cap = cap_match_func(cap, match_args))))
return cap;
((found = cap_match_func(cap, match_args))))
return found;
/* Search container list */
list_foreach_struct(cap, &task->container->cap_list.caps, list)
if (cap_type(cap) == cap_type &&
((cap = cap_match_func(cap, match_args))))
return cap;
((found = cap_match_func(cap, match_args))))
return found;
return 0;
}
@@ -144,6 +160,24 @@ struct sys_mutex_args {
unsigned int op;
};
/*
* Check broadly the ability to do mutex ops. Check it by
* the thread, space or container, (i.e. the group that can
* do this operation broadly)
*
* Note, that we check mutex_address elsewhere as a quick,
* per-task virt_to_phys translation that would not get
* easily/quickly satisfied by a memory capability checking.
*
* While this is not %100 right from a capability checking
* point-of-view, it is a shortcut that works and makes sense.
*
* For sake of completion, the right way to do it would be to
* add MUTEX_LOCKABLE, MUTEX_UNLOCKABLE attributes to both
* virtual and physical memory caps of a task, search those
* to validate the address. But we would have to translate
* from the page tables either ways.
*/
struct capability *
cap_match_mutex(struct capability *cap, void *args)
{
@@ -174,20 +208,6 @@ cap_match_mutex(struct capability *cap, void *args)
return cap;
}
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
{
struct sys_mutex_args args = {
.address = mutex_address,
.op = mutex_op,
};
if (!(cap_find(current, cap_match_mutex,
&args, CAP_TYPE_UMUTEX)))
return -ENOCAP;
return 0;
}
struct sys_capctrl_args {
unsigned int req;
unsigned int flags;
@@ -237,21 +257,6 @@ cap_match_capctrl(struct capability *cap, void *args_ptr)
return cap;
}
int cap_cap_check(struct ktcb *task, unsigned int req, unsigned int flags)
{
struct sys_capctrl_args args = {
.req = req,
.flags = flags,
.task = task,
};
if (!(cap_find(task, cap_match_capctrl,
&args, CAP_TYPE_CAP)))
return -ENOCAP;
return 0;
}
struct sys_ipc_args {
struct ktcb *task;
unsigned int ipc_type;
@@ -307,40 +312,6 @@ cap_match_ipc(struct capability *cap, void *args_ptr)
return cap;
}
/*
* Limitation: We currently only check from sender's
* perspective. Sender always targets a real thread.
* Does sender have the right to do this ipc?
*/
int cap_ipc_check(l4id_t to, l4id_t from,
unsigned int flags, unsigned int ipc_type)
{
struct ktcb *target;
struct sys_ipc_args args;
/* Receivers can get away from us (for now) */
if (ipc_type != IPC_SEND && ipc_type != IPC_SENDRECV)
return 0;
/*
* We're the sender, meaning we have
* a real target
*/
if (!(target = tcb_find(to)))
return -ESRCH;
/* Set up other args */
args.flags = flags;
args.ipc_type = ipc_type;
args.task = target;
if (!(cap_find(target, cap_match_ipc,
&args, CAP_TYPE_IPC)))
return -ENOCAP;
return 0;
}
struct sys_exregs_args {
struct exregs_data *exregs;
struct ktcb *task;
@@ -397,20 +368,6 @@ cap_match_exregs(struct capability *cap, void *args_ptr)
return cap;
}
int cap_exregs_check(struct ktcb *task, struct exregs_data *exregs)
{
struct sys_exregs_args args = {
.exregs = exregs,
.task = task,
};
if (!(cap_find(task, cap_match_exregs,
&args, CAP_TYPE_EXREGS)))
return -ENOCAP;
return 0;
}
/*
* FIXME: Issues on capabilities:
*
@@ -456,26 +413,44 @@ struct capability *cap_match_thread(struct capability *cap,
{
struct sys_tctrl_args *args = args_ptr;
struct ktcb *target = args->task;
unsigned int action_flags = args->flags & THREAD_ACTION_MASK;
/* Check operation privileges */
if (args->flags & THREAD_CREATE)
switch (action_flags) {
case THREAD_CREATE:
if (!(cap->access & CAP_TCTRL_CREATE))
return 0;
if (args->flags & THREAD_DESTROY)
break;
case THREAD_DESTROY:
if (!(cap->access & CAP_TCTRL_DESTROY))
return 0;
if (args->flags & THREAD_SUSPEND)
break;
case THREAD_SUSPEND:
if (!(cap->access & CAP_TCTRL_SUSPEND))
return 0;
if (args->flags & THREAD_RESUME)
if (!(cap->access & CAP_TCTRL_RESUME))
break;
case THREAD_RUN:
if (!(cap->access & CAP_TCTRL_RUN))
return 0;
break;
case THREAD_RECYCLE:
if (!(cap->access & CAP_TCTRL_RECYCLE))
return 0;
break;
case THREAD_WAIT:
if (!(cap->access & CAP_TCTRL_WAIT))
return 0;
break;
default:
/* We refuse to accept anything else */
return 0;
}
/* If no target and create, or vice versa, it really is a bug */
BUG_ON(!target && !(args->flags & THREAD_CREATE));
BUG_ON(target && (args->flags & THREAD_CREATE));
BUG_ON(!target && action_flags != THREAD_CREATE);
BUG_ON(target && action_flags == THREAD_CREATE);
if (args->flags & THREAD_CREATE) {
if (action_flags == THREAD_CREATE) {
/*
* FIXME: Add cid to task_ids arg.
*
@@ -490,7 +465,7 @@ struct capability *cap_match_thread(struct capability *cap,
return 0;
if (cap->resid != current->container->cid)
return 0;
/* Resource type and it match, success */
/* Resource type and id match, success */
return cap;
}
@@ -517,23 +492,6 @@ struct capability *cap_match_thread(struct capability *cap,
return cap;
}
int cap_thread_check(struct ktcb *task,
unsigned int flags,
struct task_ids *ids)
{
struct sys_tctrl_args args = {
.task = task,
.flags = flags,
.ids = ids,
};
if (!(cap_find(task, cap_match_thread,
&args, CAP_TYPE_TCTRL)))
return -ENOCAP;
return 0;
}
struct sys_map_args {
struct ktcb *task;
unsigned long phys;
@@ -541,7 +499,6 @@ struct sys_map_args {
unsigned long npages;
unsigned int flags;
unsigned int rtype;
l4id_t tid;
};
/*
@@ -589,7 +546,9 @@ struct capability *cap_match_mem(struct capability *cap,
return cap;
/*
* TODO: Does it make sense to have a meaningful resid field
* FIXME:
*
* Does it make sense to have a meaningful resid field
* in a memory resource? E.g. Which resources may I map it to?
* It might, as I can map an arbitrary mapping to an arbitrary
* thread in my container and break it's memory integrity.
@@ -601,32 +560,163 @@ struct capability *cap_match_mem(struct capability *cap,
*/
}
int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt,
unsigned long npages, unsigned int flags, l4id_t tid)
#if defined(CONFIG_CAPABILITIES)
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
{
struct sys_mutex_args args = {
.address = mutex_address,
.op = mutex_op,
};
if (!(cap_find(current, cap_match_mutex,
&args, CAP_TYPE_UMUTEX)))
return -ENOCAP;
return 0;
}
int cap_cap_check(struct ktcb *task, unsigned int req, unsigned int flags)
{
struct sys_capctrl_args args = {
.req = req,
.flags = flags,
.task = task,
};
if (!(cap_find(current, cap_match_capctrl,
&args, CAP_TYPE_CAP)))
return -ENOCAP;
return 0;
}
int cap_map_check(struct ktcb *target, unsigned long phys, unsigned long virt,
unsigned long npages, unsigned int flags)
{
struct capability *physmem, *virtmem;
struct sys_map_args args = {
.task = task,
.task = target,
.phys = phys,
.virt = virt,
.npages = npages,
.flags = flags,
.tid = tid,
};
args.rtype = CAP_RTYPE_PHYSMEM;
if (!(physmem = cap_find(task, cap_match_mem,
if (!(physmem = cap_find(current, cap_match_mem,
&args, CAP_TYPE_MAP)))
return -ENOCAP;
args.rtype = CAP_RTYPE_VIRTMEM;
if (!(virtmem = cap_find(task, cap_match_mem,
if (!(virtmem = cap_find(current, cap_match_mem,
&args, CAP_TYPE_MAP)))
return -ENOCAP;
return 0;
}
/*
* Limitation: We currently only check from sender's
* perspective. Sender always targets a real thread.
* Does sender have the right to do this ipc?
*/
int cap_ipc_check(l4id_t to, l4id_t from,
unsigned int flags, unsigned int ipc_type)
{
struct ktcb *target;
struct sys_ipc_args args;
/* Receivers can get away from us (for now) */
if (ipc_type != IPC_SEND && ipc_type != IPC_SENDRECV)
return 0;
/*
* We're the sender, meaning we have
* a real target
*/
if (!(target = tcb_find(to)))
return -ESRCH;
/* Set up other args */
args.flags = flags;
args.ipc_type = ipc_type;
args.task = target;
if (!(cap_find(current, cap_match_ipc,
&args, CAP_TYPE_IPC)))
return -ENOCAP;
return 0;
}
int cap_exregs_check(struct ktcb *task, struct exregs_data *exregs)
{
struct sys_exregs_args args = {
.exregs = exregs,
.task = task,
};
/* We always search for current's caps */
if (!(cap_find(current, cap_match_exregs,
&args, CAP_TYPE_EXREGS)))
return -ENOCAP;
return 0;
}
int cap_thread_check(struct ktcb *task,
unsigned int flags,
struct task_ids *ids)
{
struct sys_tctrl_args args = {
.task = task,
.flags = flags,
.ids = ids,
};
if (!(cap_find(current, cap_match_thread,
&args, CAP_TYPE_TCTRL)))
return -ENOCAP;
return 0;
}
#else /* Meaning !CONFIG_CAPABILITIES */
int cap_mutex_check(unsigned long mutex_address, int mutex_op)
{
return 0;
}
int cap_cap_check(struct ktcb *task, unsigned int req, unsigned int flags)
{
return 0;
}
int cap_ipc_check(l4id_t to, l4id_t from,
unsigned int flags, unsigned int ipc_type)
{
return 0;
}
int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt,
unsigned long npages, unsigned int flags)
{
return 0;
}
int cap_exregs_check(struct ktcb *task, struct exregs_data *exregs)
{
return 0;
}
int cap_thread_check(struct ktcb *task,
unsigned int flags,
struct task_ids *ids)
{
return 0;
}
#endif
/*
* FIXME:
*
@@ -667,7 +757,6 @@ int capability_set_resource_id(struct capability *cap)
case CAP_RTYPE_TGROUP:
case CAP_RTYPE_SPACE:
case CAP_RTYPE_CONTAINER:
case CAP_RTYPE_UMUTEX:
break;
}
return 0;