Progress on capabilities

Capabilities will be shared among collection of threads. A pager
will have a right to share its own capabilities with its space,
its thread group and its container.

Currently sharing is possible with only all of the caps. Next,
it will be support for cap splitting, granting, and partial sharing
and granting.
This commit is contained in:
Bahadir Balban
2009-10-22 14:04:25 +03:00
parent c6bdd65e48
commit 0f9ea9674c
14 changed files with 298 additions and 47 deletions

View File

@@ -200,7 +200,7 @@ int read_pager_capabilities()
caparray = alloc_bootmem(sizeof(struct capability) * ncaps, 0);
/* Read all capabilities */
if ((err = l4_capability_control(CAP_CONTROL_READ_CAPS,
if ((err = l4_capability_control(CAP_CONTROL_READ,
0, caparray)) < 0) {
printf("l4_capability_control() reading of "
"capabilities failed.\n Could not "

View File

@@ -8,6 +8,11 @@
/* Capability syscall request types */
#define CAP_CONTROL_NCAPS 0
#define CAP_CONTROL_READ_CAPS 1
#define CAP_CONTROL_READ 1
#define CAP_CONTROL_SHARE 2
#define CAP_SHARE_WITH_SPACE 1
#define CAP_SHARE_WITH_CONTAINER 2
#define CAP_SHARE_WITH_TGROUP 4
#endif /* __API_CAPABILITY_H__ */

View File

@@ -8,6 +8,16 @@
#include <l4/lib/list.h>
/*
* Some resources that capabilities possess don't
* have unique ids or need ids at all.
*
* E.g. a threadpool does not need a resource id.
* A virtual memory capability does not require
* a resource id, its capid is sufficient.
*/
#define CAP_RESID_NONE -1
/*
* A capability is a unique representation of security
* qualifiers on a particular resource.
@@ -65,6 +75,7 @@ struct capability {
};
struct cap_list {
int ktcb_refs;
int ncaps;
struct link caps;
};
@@ -87,12 +98,43 @@ static inline void cap_list_insert(struct capability *cap,
clist->ncaps++;
}
/* Detach a whole list of capabilities from list head */
static inline struct capability *
cap_list_detach(struct cap_list *clist)
{
struct link *list = list_detach(&clist->caps);
clist->ncaps = 0;
return link_to_struct(list, struct capability, list);
}
/* Attach a whole list of capabilities to list head */
static inline void cap_list_attach(struct capability *cap,
struct cap_list *clist)
{
/* Attach as if cap is the list and clist is the element */
list_insert(&clist->caps, &cap->list);
/* Count the number of caps attached */
list_foreach_struct(cap, &clist->caps, list)
clist->ncaps++;
}
static inline void cap_list_move(struct cap_list *to,
struct cap_list *from)
{
struct capability *cap_head = cap_list_detach(from);
cap_list_attach(cap_head, to);
}
struct ktcb;
/* Capability checking for quantitative capabilities */
int capability_consume(struct capability *cap, int quantity);
int capability_free(struct capability *cap, int quantity);
struct capability *capability_find_by_rtype(struct cap_list *clist,
struct capability *capability_find_by_rtype(struct ktcb *task,
unsigned int rtype);
struct capability *cap_list_find_by_rtype(struct cap_list *clist,
unsigned int rtype);
#if 0
/* Virtual memory space allocated to container */
struct capability cap_virtmap = {

View File

@@ -48,6 +48,7 @@ struct container {
struct id_pool *space_id_pool;
struct mutex_queue_head mutex_queue_head; /* Userspace mutex list */
struct cap_list cap_list; /* Capabilities shared by whole container */
/*
* Capabilities that apply to this container

View File

@@ -24,6 +24,7 @@
#include <l4/lib/list.h>
#include <l4/lib/mutex.h>
#include <l4/lib/idpool.h>
#include <l4/generic/capability.h>
#include INC_SUBARCH(mm.h)
/* A simple page table with a reference count */
@@ -32,6 +33,9 @@ struct address_space {
struct link list;
struct mutex lock;
pgd_table_t *pgd;
/* Capabilities shared by threads in same space */
struct cap_list cap_list;
int ktcb_refs;
};

View File

@@ -102,9 +102,9 @@ struct ktcb {
struct container *container;
struct pager *pager;
/* Capability list */
struct cap_list *cap_list_ptr;
/* Capability lists */
struct cap_list cap_list;
struct cap_list tgr_cap_list;
/* Fields for ipc rendezvous */
struct waitqueue_head wqh_recv;

View File

@@ -73,6 +73,18 @@ static inline void list_remove_init(struct link *link)
link->prev = link;
}
/* Cuts the whole list from head and returns it */
static inline struct link *list_detach(struct link *head)
{
struct link *next = head->next;
/* Detach head from rest of the list */
list_remove_init(head);
/* Return detached list */
return next;
}
static inline int list_empty(struct link *list)
{
return list->prev == list && list->next == list;

View File

@@ -10,10 +10,10 @@
#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;
@@ -28,24 +28,56 @@ int read_task_capabilities(void *userbuf)
return -EPERM;
/* Determine size of pager capabilities */
copy_size = current->cap_list_ptr->ncaps * sizeof(*cap);
copy_size = current->cap_list.ncaps * sizeof(*cap);
/* Validate user buffer for this copy size */
if ((err = check_access((unsigned long)userbuf, 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,
&current->cap_list_ptr->caps,
list_foreach_struct(cap, &current->cap_list.caps,
list) {
memcpy(userbuf + copy_offset, cap, sizeof(*cap));
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.
*/
int capability_share(unsigned int share_flags)
{
switch (share_flags) {
case CAP_SHARE_WITH_SPACE:
cap_list_move(&current->space->cap_list,
&current->cap_list);
break;
case CAP_SHARE_WITH_CONTAINER:
cap_list_move(&curcont->cap_list,
&current->cap_list);
break;
case CAP_SHARE_WITH_TGROUP: {
struct ktcb *tgr_leader;
BUG_ON(!(tgr_leader = tcb_find(current->tgid)));
cap_list_move(&tgr_leader->cap_list,
&current->cap_list);
break;
}
default:
return -EINVAL;
}
return 0;
}
/*
* Read, manipulate capabilities. Currently only capability read support.
*/
@@ -59,19 +91,22 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf)
if (current != current->pager->tcb)
return -EPERM;
if ((err = check_access((unsigned long)userbuf, sizeof(int),
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_ptr->ncaps;
*((int *)userbuf) = current->cap_list.ncaps;
break;
/* Return all capabilities as an array of capabilities */
case CAP_CONTROL_READ_CAPS:
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;
@@ -80,7 +115,42 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf)
}
#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)
{
if (split->valid & FIELD_TO_BIT(struct cap_split_desc, access)) {
new->access = orig->access & split->access;
orig->access &= ~split->access;
}
if (split->valid & FIELD_TO_BIT(struct cap_split_desc, size)) {
new->size = orig->size - split->size;
orig->size -= split->size;
}
if (split->valid & FIELD_TO_BIT(struct cap_split_desc, start)) {
memcap_unmap(cap, split->start, split->end);
new->size = orig->size - split->size;
orig->size -= split->size;
}
}
int capability_split(struct ktcb *recv, struct ktcb *send, struct capability *cap, struct cap_split_desc *split)
{
capability_diff(orig, new, split);
}
#endif

View File

@@ -5,7 +5,9 @@
*/
#include <l4/generic/resource.h>
#include <l4/generic/capability.h>
#include <l4/generic/container.h>
#include <l4/generic/cap-types.h>
#include <l4/generic/tcb.h>
#include <l4/api/errno.h>
#include <l4/lib/printk.h>
@@ -53,16 +55,99 @@ int capability_free(struct capability *cap, int quantity)
return 0;
}
struct capability *cap_list_find_by_rtype(struct cap_list *cap_list,
unsigned int rtype)
{
struct capability *cap;
list_foreach_struct(cap, &cap_list->caps, list)
if (cap_rtype(cap) == rtype)
return cap;
return 0;
}
/*
* Find a capability from a list by its resource type
* Search all capability lists that task is allowed.
*
* FIXME:
* Tasks won't 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.
*/
struct capability *capability_find_by_rtype(struct cap_list *clist,
struct capability *capability_find_by_rtype(struct ktcb *task,
unsigned int rtype)
{
struct capability *cap;
list_foreach_struct(cap, &clist->caps, list)
if ((cap->type & CAP_RTYPE_MASK) == rtype)
/* Search task's own list */
list_foreach_struct(cap, &task->cap_list.caps, list)
if (cap_rtype(cap) == rtype)
return cap;
/* Search space list */
list_foreach_struct(cap, &task->space->cap_list.caps, list)
if (cap_rtype(cap) == rtype)
return cap;
/* Search thread group list */
list_foreach_struct(cap, &task->tgr_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)
return cap;
return 0;
}
/*
* FIXME:
*
* Capability resource ids
*
* Currently the kernel cinfo has no resource id field. This is
* because resources are dynamically assigned an id at run-time.
*
* However, this prevents the user to specify capabilities on
* particular resources since resources aren't id-able at
* configuration time. There's also no straightforward way to
* determine which id was meant at run-time.
*
* As a solution, resources that are id-able and that are targeted
* by capabilities at configuration time should be assigned static
* ids at configuration time. Any other id-able resources that are
* subject to capabilities by run-time sharing/delegation/derivation
* etc. should be assigned their ids dynamically.
*
* Example:
*
* A capability to ipc to a particular container.
*
* When this capability is defined at configuration time, it is only
* meaningful if the container id is also supplied statically.
*
* If a pager later on generates a capability to ipc to a thread
* that it created at run-time, and grant it to another container's
* pager, (say a container thread would like to talk to another
* container's thread) it should assign the dynamically assigned
* target thread id as the capability resource id and hand it over.
*/
int capability_set_resource_id(struct capability *cap)
{
/* Identifiable resources */
switch(cap_rtype(cap)) {
case CAP_RTYPE_THREAD:
case CAP_RTYPE_TGROUP:
case CAP_RTYPE_SPACE:
case CAP_RTYPE_CONTAINER:
case CAP_RTYPE_UMUTEX:
break;
}
return 0;
}

View File

@@ -22,6 +22,7 @@ int container_init(struct container *c)
init_address_space_list(&c->space_list);
init_ktcb_list(&c->ktcb_list);
init_mutex_queue_head(&c->mutex_queue_head);
cap_list_init(&c->cap_list);
/* Init pager structs */
for (int i = 0; i < CONFIG_MAX_PAGERS_USED; i++)
@@ -73,15 +74,14 @@ int init_pager(struct pager *pager,
struct ktcb *task;
struct address_space *space;
int first = !!current_pgd;
struct capability *cap;
/*
* Initialize dummy current capability list pointer
* so that capability accounting can be done as normal
*
* FYI: We're still on bootstack instead of current's
* real stack. Hence this is a dummy.
* Set up dummy current cap_list so that cap accounting
* can be done to this pager. Note, that we're still on
* bootstack.
*/
current->cap_list_ptr = &pager->cap_list;
cap_list_move(&current->cap_list, &pager->cap_list);
/* New ktcb allocation is needed */
task = tcb_alloc_init();
@@ -112,7 +112,25 @@ int init_pager(struct pager *pager,
task->pager = pager;
task->pagerid = task->tid;
task->container = cont;
task->cap_list_ptr = &pager->cap_list;
/* Initialize uninitialized capability fields while on dummy */
list_foreach_struct(cap, &current->cap_list.caps, list) {
/* Initialize owner */
cap->owner = task->tid;
/*
* Initialize resource id, if possible.
* Currently this is a temporary hack where
* we allow only container ids and _assume_
* that container is pager's own container.
*
* See capability resource ids for info
*/
if (cap_rtype(cap) == CAP_RTYPE_CONTAINER)
cap->resid = task->container->cid;
else
cap->resid = CAP_RESID_NONE;
}
printk("%s: Mapping %lu pages from 0x%lx to 0x%lx for %s\n",
__KERNELNAME__,
@@ -124,6 +142,9 @@ int init_pager(struct pager *pager,
page_align_up(pager->memsize),
MAP_USR_DEFAULT_FLAGS, TASK_PGD(task));
/* Move capability list from dummy to task's cap list */
cap_list_move(&task->cap_list, &current->cap_list);
/* Initialize task scheduler parameters */
sched_init_task(task, TASK_PRIO_PAGER);

View File

@@ -24,7 +24,7 @@ pmd_table_t *alloc_pmd(void)
{
struct capability *cap;
if (!(cap = capability_find_by_rtype(current->cap_list_ptr,
if (!(cap = capability_find_by_rtype(current,
CAP_RTYPE_MAPPOOL)))
return 0;
@@ -38,7 +38,7 @@ struct address_space *alloc_space(void)
{
struct capability *cap;
if (!(cap = capability_find_by_rtype(current->cap_list_ptr,
if (!(cap = capability_find_by_rtype(current,
CAP_RTYPE_SPACEPOOL)))
return 0;
@@ -60,7 +60,7 @@ struct ktcb *alloc_ktcb(void)
{
struct capability *cap;
if (!(cap = capability_find_by_rtype(current->cap_list_ptr,
if (!(cap = capability_find_by_rtype(current,
CAP_RTYPE_THREADPOOL)))
return 0;
@@ -73,7 +73,8 @@ struct ktcb *alloc_ktcb(void)
/*
* This version is boot-time only and it has no
* capability checking. Imagine the case where the
* initial capabilities are created.
* initial capabilities are created and there is no
* capability to check this allocation.
*/
struct capability *boot_alloc_capability(void)
{
@@ -84,7 +85,7 @@ struct capability *alloc_capability(void)
{
struct capability *cap;
if (!(cap = capability_find_by_rtype(current->cap_list_ptr,
if (!(cap = capability_find_by_rtype(current,
CAP_RTYPE_CAPPOOL)))
return 0;
@@ -103,7 +104,7 @@ struct mutex_queue *alloc_user_mutex(void)
{
struct capability *cap;
if (!(cap = capability_find_by_rtype(current->pager->tcb->cap_list_ptr,
if (!(cap = capability_find_by_rtype(current,
CAP_RTYPE_MUTEXPOOL)))
return 0;
@@ -122,7 +123,7 @@ void free_pmd(void *addr)
{
struct capability *cap;
BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr,
BUG_ON(!(cap = capability_find_by_rtype(current,
CAP_RTYPE_MAPPOOL)));
capability_free(cap, 1);
@@ -133,7 +134,7 @@ void free_space(void *addr)
{
struct capability *cap;
BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr,
BUG_ON(!(cap = capability_find_by_rtype(current,
CAP_RTYPE_SPACEPOOL)));
capability_free(cap, 1);
@@ -144,7 +145,7 @@ void free_ktcb(void *addr)
{
struct capability *cap;
BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr,
BUG_ON(!(cap = capability_find_by_rtype(current,
CAP_RTYPE_THREADPOOL)));
capability_free(cap, 1);
@@ -155,7 +156,7 @@ void free_capability(void *addr)
{
struct capability *cap;
BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr,
BUG_ON(!(cap = capability_find_by_rtype(current,
CAP_RTYPE_CAPPOOL)));
capability_free(cap, 1);
@@ -171,7 +172,7 @@ void free_user_mutex(void *addr)
{
struct capability *cap;
BUG_ON(!(cap = capability_find_by_rtype(current->pager->tcb->cap_list_ptr,
BUG_ON(!(cap = capability_find_by_rtype(current,
CAP_RTYPE_MUTEXPOOL)));
capability_free(cap, 1);
@@ -399,6 +400,7 @@ void init_kernel_resources(struct kernel_resources *kres)
memcap_unmap(&kres->physmem_free, kernel_area->start,
kernel_area->end);
/* Initialize zombie pager list */
init_ktcb_list(&kres->zombie_list);
/* TODO:
@@ -443,8 +445,8 @@ int copy_pager_info(struct pager *pager, struct pager_info *pinfo)
* Find pager's capability capability, check its
* current use count and initialize it
*/
cap = capability_find_by_rtype(&pager->cap_list,
CAP_RTYPE_CAPPOOL);
cap = cap_list_find_by_rtype(&pager->cap_list,
CAP_RTYPE_CAPPOOL);
/* Verify that we did not excess allocated */
if (!cap || cap->size < pinfo->ncaps) {
@@ -497,6 +499,14 @@ void setup_containers(struct boot_resources *bootres,
*/
current_pgd = realloc_page_tables();
/* Move it back
*
* FIXME: Merge until this part of code with
* kres_setup_capabilities and init_system_resources
* it doesn't look good.
*/
cap_list_move(&kres->non_memory_caps, &current->cap_list);
/* Create all containers but leave pagers */
for (int i = 0; i < bootres->nconts; i++) {
/* Allocate & init container */
@@ -575,7 +585,7 @@ void kres_setup_capabilities(struct boot_resources *bootres,
cap_list_insert(cap, &kres->non_memory_caps);
/* Set up dummy current cap-list for below functions to use */
current->cap_list_ptr = &kres->non_memory_caps;
cap_list_move(&current->cap_list, &kres->non_memory_caps);
copy_boot_capabilities(&kres->physmem_used);
copy_boot_capabilities(&kres->physmem_free);
@@ -836,8 +846,6 @@ int setup_boot_resources(struct boot_resources *bootres,
}
/*
* FIXME: Add error handling
*
* Initializes all system resources and handling of those
* resources. First descriptions are done by allocating from
* boot memory, once memory caches are initialized, boot
@@ -845,7 +853,6 @@ int setup_boot_resources(struct boot_resources *bootres,
*/
int init_system_resources(struct kernel_resources *kres)
{
/* FIXME: Count kernel resources */
struct boot_resources bootres;
memset(&bootres, 0, sizeof(bootres));

View File

@@ -107,6 +107,7 @@ struct address_space *address_space_create(struct address_space *orig)
/* Initialize space structure */
link_init(&space->list);
cap_list_init(&space->cap_list);
mutex_init(&space->lock);
space->pgd = pgd;

View File

@@ -30,7 +30,8 @@ void tcb_init(struct ktcb *new)
link_init(&new->task_list);
mutex_init(&new->thread_control_lock);
link_init(&new->cap_list.caps);
cap_list_init(&new->cap_list);
cap_list_init(&new->tgr_cap_list);
/* Initialise task's scheduling state and parameters. */
sched_init_task(new, TASK_PRIO_NORMAL);

View File

@@ -5,18 +5,20 @@ replacement=(w x y z)
# Test that we have both arguments
if [ -z "$1" ]; then
echo Usage: replace_words ORIGINAL REPLACEMENT
echo Usage: replace_words DIRNAME ORIGINAL REPLACEMENT
exit
fi
for ((i=0;i<1;i++));
do
orig=${original[$i]}
repl=${replacement[$i]}
echo $orig to $repl
#orig=${original[$i]}
#repl=${replacement[$i]}
orig=$2
repl=$3
for filename in `find $1 -name '*.[ch]'`
do
echo Replacing $orig with $repl in $filename
sed -i -e "s/$orig/$repl/g" $filename
done
done