From 3728e7ef1e298423b483452f95c436b45298d213 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 7 Nov 2009 15:29:52 +0200 Subject: [PATCH] Capability manipulation syscalls Support for capability replicate, share, grant, deduce, and split. The code builds, but hasn't been tested. --- conts/posix/mm0/mm/init.c | 64 +++- include/l4/api/capability.h | 25 +- include/l4/api/syscall.h | 3 +- include/l4/generic/cap-types.h | 29 +- include/l4/generic/capability.h | 3 +- src/api/cap.c | 549 ++++++++++++++++++++++++-------- src/generic/capability.c | 47 ++- src/glue/arm/systable.c | 6 +- 8 files changed, 562 insertions(+), 164 deletions(-) diff --git a/conts/posix/mm0/mm/init.c b/conts/posix/mm0/mm/init.c index 9d3d228..d7fb6c8 100644 --- a/conts/posix/mm0/mm/init.c +++ b/conts/posix/mm0/mm/init.c @@ -179,7 +179,59 @@ void copy_boot_capabilities(int ncaps) capability_list.ncaps = ncaps; } -int read_pager_capabilities() +/* + * Our paged userspace shall have only the capability to do + * ipc to us, and use no other system call. (Other than + * the trivial ones like thread_switch() and l4_getid) + */ +int setup_children_caps(void) +{ + struct capability ipc_cap; + struct task_ids ids; + + l4_getids(&ids); + + /* Create a brand new capability */ + ipc_cap.owner = ids.tid; /* Owned by us */ + ipc_cap.resid = __cid(ids.tid); /* This container is target resource */ + + /* + * IPC capability, with container set as + * target resource type. + * + * This literally means the capability can target + * all of the container, e.g. a capability to ipc + * to any member of this container. + */ + ipc_cap.type = CAP_TYPE_IPC | CAP_RTYPE_CONTAINER; + ipc_cap.access = CAP_IPC_SEND | CAP_IPC_RECV | CAP_IPC_SHORT | + CAP_IPC_FULL | CAP_IPC_EXTENDED | CAP_IPC_ASYNC; + + /* Create the capability for self */ + if ((err = l4_capability_control(CAP_CONTROL_CREATE, 0, 0, 0, &ipc_cap)) < 0) { + printf("l4_capability_control() sharing of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_SHARE request.\n"); + BUG(); + } + + /* + * Share it with our container. + * + * This effectively enables all threads in this container + * to communicate + */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE | CAP_SHARE_SINGLE, + CAP_SHARE_CONTAINER, 0)) < 0) { + printf("l4_capability_control() sharing of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_SHARE request.\n"); + BUG(); + } + return 0; +} + +int read_pager_caps() { int ncaps; int err; @@ -207,16 +259,6 @@ int read_pager_capabilities() BUG(); } - /* Share all of them with paged children */ - if ((err = l4_capability_control(CAP_CONTROL_SHARE, - CAP_SHARE_CONTAINER, - 0)) < 0) { - printf("l4_capability_control() sharing of " - "capabilities failed.\n Could not " - "complete CAP_CONTROL_SHARE request.\n"); - BUG(); - } - /* Copy them to real allocated structures */ copy_boot_capabilities(ncaps); diff --git a/include/l4/api/capability.h b/include/l4/api/capability.h index 8b53411..9c83eda 100644 --- a/include/l4/api/capability.h +++ b/include/l4/api/capability.h @@ -7,18 +7,21 @@ #define __API_CAPABILITY_H__ /* Capability syscall request types */ -#define CAP_CONTROL_NCAPS 0x00 -#define CAP_CONTROL_READ 0x01 -#define CAP_CONTROL_SHARE 0x02 -#define CAP_CONTROL_GRANT 0x03 -#define CAP_CONTROL_MODIFY 0x05 +#define CAP_CONTROL_NCAPS 0x00000000 +#define CAP_CONTROL_READ 0x00000001 +#define CAP_CONTROL_SHARE 0x00000002 +#define CAP_CONTROL_GRANT 0x00000003 +#define CAP_CONTROL_REPLICATE 0x00000005 +#define CAP_CONTROL_SPLIT 0x00000006 +#define CAP_CONTROL_DEDUCE 0x00000007 -#define CAP_SHARE_MASK 0x1F -#define CAP_SHARE_SPACE 0x01 -#define CAP_SHARE_CONTAINER 0x02 -#define CAP_SHARE_GROUP 0x04 -#define CAP_SHARE_CHILD 0x08 /* All that we are pager of */ -#define CAP_SHARE_SIBLING 0x10 /* All that have a common pager */ +#define CAP_SHARE_MASK 0x00000003 +#define CAP_SHARE_SINGLE 0x00000001 +#define CAP_SHARE_ALL 0x00000002 + +#define CAP_GRANT_MASK 0x00000003 +#define CAP_GRANT_SINGLE 0x00000001 +#define CAP_GRANT_ALL 0x00000002 /* Task's primary capability list */ #define TASK_CAP_LIST(task) \ diff --git a/include/l4/api/syscall.h b/include/l4/api/syscall.h index 36d6751..249532a 100644 --- a/include/l4/api/syscall.h +++ b/include/l4/api/syscall.h @@ -42,7 +42,8 @@ int sys_ipc_control(void); int sys_map(unsigned long phys, unsigned long virt, unsigned long npages, unsigned int flags, l4id_t tid); int sys_getid(struct task_ids *ids); -int sys_capability_control(unsigned int req, unsigned int flags, void *addr); +int sys_capability_control(unsigned int req, unsigned int flags, + l4id_t capid, l4id_t target, void *addr); int sys_container_control(unsigned int req, unsigned int flags, void *addr); int sys_time(struct timeval *tv, int set); int sys_mutex_control(unsigned long mutex_address, int mutex_op); diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index f4cbf33..69395bd 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -26,23 +26,29 @@ */ #define CAP_RTYPE_MASK 0xFFFF0000 #define CAP_RTYPE_THREAD (1 << 16) -#define CAP_RTYPE_TGROUP (1 << 17) -#define CAP_RTYPE_SPACE (1 << 18) -#define CAP_RTYPE_CONTAINER (1 << 19) -#define CAP_RTYPE_PGGROUP (1 << 20) /* Group of paged threads */ -#define CAP_RTYPE_CPUPOOL (1 << 21) -#define CAP_RTYPE_THREADPOOL (1 << 22) -#define CAP_RTYPE_SPACEPOOL (1 << 23) -#define CAP_RTYPE_MUTEXPOOL (1 << 24) -#define CAP_RTYPE_MAPPOOL (1 << 25) /* For pmd spending */ -#define CAP_RTYPE_CAPPOOL (1 << 26) /* For new cap generation */ +#define CAP_RTYPE_SPACE (1 << 17) +#define CAP_RTYPE_CONTAINER (1 << 18) +#define CAP_RTYPE_CPUPOOL (1 << 19) +#define CAP_RTYPE_THREADPOOL (1 << 20) +#define CAP_RTYPE_SPACEPOOL (1 << 21) +#define CAP_RTYPE_MUTEXPOOL (1 << 22) +#define CAP_RTYPE_MAPPOOL (1 << 23) /* For pmd spending */ +#define CAP_RTYPE_CAPPOOL (1 << 24) /* For new cap generation */ #define cap_rtype(c) ((c)->type & CAP_RTYPE_MASK) +#define cap_set_rtype(c, rtype) \ + {(c)->type &= CAP_RTYPE_MASK; \ + (c)->type |= CAP_RTYPE_MASK & rtype;} /* * Access permissions */ +/* Generic permissions */ +#define CAP_CHANGEABLE (1 << 28) /* Can modify contents */ +#define CAP_TRANSFERABLE (1 << 29) /* Can grant or share it */ +#define CAP_REPLICABLE (1 << 30) /* Can create copies */ + /* Thread control capability */ #define CAP_TCTRL_CREATE (1 << 0) #define CAP_TCTRL_DESTROY (1 << 1) @@ -96,5 +102,8 @@ #define CAP_CAP_GRANT (1 << 1) #define CAP_CAP_READ (1 << 2) #define CAP_CAP_SHARE (1 << 3) +#define CAP_CAP_REPLICATE (1 << 4) +#define CAP_CAP_SPLIT (1 << 5) +#define CAP_CAP_DEDUCE (1 << 6) #endif /* __CAP_TYPES_H__ */ diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index 61b2da5..af22ddd 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -66,7 +66,7 @@ struct capability { /* Capability limits/permissions */ u32 access; /* Permitted operations */ - /* Limits on the resource */ + /* Limits on the resource (NOTE: must never have signed type) */ unsigned long start; /* Resource start value */ unsigned long end; /* Resource end value */ unsigned long size; /* Resource size */ @@ -139,6 +139,7 @@ struct capability *capability_find_by_rtype(struct ktcb *task, struct capability *cap_list_find_by_rtype(struct cap_list *clist, unsigned int rtype); +struct capability *cap_find_byid(l4id_t capid); /* Capability checking on system calls */ int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt, diff --git a/src/api/cap.c b/src/api/cap.c index c456a07..cd16b05 100644 --- a/src/api/cap.c +++ b/src/api/cap.c @@ -1,14 +1,14 @@ /* * Capability manipulation syscall. * - * The heart of Codezero security - * mechanisms lay here. + * The entry to Codezero security + * mechanisms. * * Copyright (C) 2009 Bahadir Balban */ - #include #include +#include #include #include #include @@ -16,14 +16,25 @@ /* * FIXME: This is reading only a single list - * there may be more than one + * there may be more than one. */ -int read_task_capabilities(void *userbuf) +int cap_read_all(struct capability *caparray) { - int copy_size, copy_offset = 0; struct capability *cap; + int total_size, capidx = 0; int err; + /* + * Determine size of pager capabilities + * (FIXME: partial!) + */ + total_size = TASK_CAP_LIST(current)->ncaps + * sizeof(*cap); + if ((err = check_access((unsigned long)caparray, + total_size, + MAP_USR_RW_FLAGS, 1)) < 0) + return err; + /* * Currently only pagers can * read their own capabilities @@ -31,88 +42,404 @@ int read_task_capabilities(void *userbuf) if (current->tid != current->pagerid) return -EPERM; - /* Determine size of pager capabilities (FIXME: partial!) */ - copy_size = TASK_CAP_LIST(current)->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, &TASK_CAP_LIST(current)->caps, + list_foreach_struct(cap, + &TASK_CAP_LIST(current)->caps, list) { - memcpy(userbuf + copy_offset, - cap, sizeof(*cap)); - copy_offset += sizeof(*cap); + memcpy(&caparray[capidx], cap, sizeof(*cap)); + capidx++; } 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. + * Shares single cap. If you are sharing, there is + * only one target that makes sense, that is your + * own container. */ -int capability_share(unsigned int share_flags) +int cap_share_single(l4id_t capid) { - switch (share_flags) { - case CAP_SHARE_SPACE: - cap_list_move(¤t->space->cap_list, - TASK_CAP_LIST(current)); - break; - case CAP_SHARE_CONTAINER: - cap_list_move(&curcont->cap_list, - TASK_CAP_LIST(current)); - break; -#if 0 - 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); + struct capability *cap; - /* - * 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; + if (!(cap = cap_find_byid(capid))) + return -EEXIST; - BUG_ON(!(tgroup_leader = tcb_find(current->tgid))); - cap_list_move(&tgroup_leader->tgroup_cap_list, - ¤t->cap_list); - break; - } -#endif - default: + if (cap->owner != current->tid) + return -EPERM; + + /* First remove it from its list */ + list_remove(&cap->list); + + /* Place it where it is shared */ + cap_list_insert(cap, &curcont->cap_list); + + return 0; +} + +/* Shares the whole list */ +int cap_share_all(void) +{ + cap_list_move(&curcont->cap_list, + TASK_CAP_LIST(current)); + return 0; +} + +int cap_share(l4id_t capid, unsigned int flags) +{ + if (flags & CAP_SHARE_SINGLE) + cap_share_single(capid); + else if (flags & CAP_SHARE_ALL) + cap_share_all(); + else return -EINVAL; + return 0; +} + +/* Grants all caps */ +int cap_grant_all(l4id_t tid) +{ + struct ktcb *target; + struct capability *cap_head, *cap; + int err; + + if (!(target = tcb_find(tid))) + return -ESRCH; + + /* Detach all caps */ + cap_head = cap_list_detach(TASK_CAP_LIST(current)); + + list_foreach_struct(cap, &cap_head->list, list) { + /* Change ownership */ + cap->owner = target->tid; + + /* + * Sanity check: granted cap cannot have used + * quantity. Otherwise how else the original + * users of the cap free them? + */ + if (cap->used) { + err = -EPERM; + goto out_err; + } } + + /* Attach all to target */ + cap_list_attach(cap_head, TASK_CAP_LIST(target)); + return 0; + +out_err: + /* Attach it back to original */ + cap_list_attach(cap_head, TASK_CAP_LIST(current)); + return err; +} + +int cap_grant_single(l4id_t capid, l4id_t tid) +{ + struct capability *cap; + struct ktcb *target; + + if (!(cap = cap_find_byid(capid))) + return -EEXIST; + + if (!(target = tcb_find(tid))) + return -ESRCH; + + if (cap->owner != current->tid) + return -EPERM; + + /* Granted cap cannot have used quantity */ + if (cap->used) + return -EPERM; + + /* First remove it from its list */ + list_remove(&cap->list); + + /* Change ownership */ + cap->owner = target->tid; + + /* Place it where it is granted */ + cap_list_insert(cap, TASK_CAP_LIST(target)); + + return 0; +} + +int cap_grant(unsigned int flags, l4id_t capid, l4id_t tid) +{ + if (flags & CAP_GRANT_SINGLE) + cap_grant_single(capid, tid); + else if (flags & CAP_GRANT_ALL) + cap_grant_all(tid); + else + return -EINVAL; + return 0; +} + +/* + * Deduction can be by access permissions, start, end, size + * fields, or the target resource type. Inter-container + * deduction is not allowed. + * + * Target resource deduction denotes reducing the applicable + * space of the target, e.g. from a container to a space in + * that container. + * + * NOTE: If there is no target deduction, you cannot change + * resid, as this is forbidden. + * + * Imagine a space cap, it cannot be deduced to become applicable + * to another space, i.e a space is in same privilege level. + * But a container-wide cap can be reduced to be applied on + * a space in that container (thus changing the resid to that + * space's id) + * + * capid: Id of original capability + * new: Userspace pointer to new state of capability + * that is desired. + * + * orig = deduced; + */ +int cap_deduce(l4id_t capid, struct capability *new) +{ + struct capability *orig; + struct address_space *sp; + + /* Find original capability */ + if (!(orig = cap_find_byid(capid))) + return -EEXIST; + + /* Check that caller is owner */ + if (orig->owner != current->tid) + return -ENOCAP; + + /* Check that it is deducable */ + if (!(orig->access & CAP_CHANGEABLE)) + return -ENOCAP; + + /* Check target resource deduction */ + if (cap_rtype(new) != cap_rtype(orig)) { + /* An rtype deduction is always a space */ + if (cap_rtype(new) != CAP_RTYPE_SPACE) + return -ENOCAP; + + /* Assign new type to original cap */ + cap_set_rtype(orig, cap_rtype(new)); + + /* + * Find out if this space exists. + * + * Note address space search is + * local only. Only thread searches + * are global. + */ + if (!(sp = address_space_find(new->resid))) + return -ENOCAP; + + /* Success. Assign the space id to orig cap */ + orig->resid = sp->spid; + } + + /* Check permissions for deduction */ + if (orig->access) { + /* New cannot have more bits than original */ + if ((orig->access & new->access) != new->access) + return -EINVAL; + /* New cannot make original redundant */ + if (new->access == 0) + return -EINVAL; + + /* Deduce bits of orig */ + orig->access &= new->access; + } + + if (new->size) { + /* New can't have more, or make original redundant */ + if (new->size >= orig->size) + return -EINVAL; + + /* + * Can't make reduction on used ones, so there + * must be enough available ones + */ + if (new->size < orig->used) + return -EPERM; + orig->size = new->size; + } + + /* Range-like permissions can't be deduced */ + if (orig->start != new->start || + orig->end != new->end) + return -EPERM; + + return 0; +} + +/* + * Splits a capability + * + * Pools of typed memory objects can't be replicated, and + * deduced that way, as replication would temporarily double + * their size. So they are split in place. + * + * Splitting occurs by diff'ing resources possessed between + * capabilities. + * + * capid: Original capability that is valid. + * diff: New capability that we want to split out. + * + * orig = orig - diff; + * new = diff; + */ +int cap_split(l4id_t capid, struct capability *diff) +{ + struct capability *orig, *new; + + /* Find original capability */ + if (!(orig = cap_find_byid(capid))) + return -ENOCAP; + + /* Check target type/resid/owner is the same */ + if (orig->type != diff->type || + orig->resid != diff->resid || + orig->owner != diff->owner) + return -EINVAL; + + /* Check that caller is owner */ + if (orig->owner != current->tid) + return -ENOCAP; + + /* Check that it is splitable */ + if (!(orig->access & CAP_CHANGEABLE)) + return -ENOCAP; + + /* Create new */ + if (!(new = capability_create())) + return -ENOCAP; + + /* Check access bits usage and split */ + if (orig->access) { + /* Split one can't have more bits than original */ + if ((orig->access & diff->access) != diff->access) { + free_capability(new); + return -EINVAL; + } + + /* Split one cannot make original redundant */ + if ((orig->access & ~diff->access) == 0) { + free_capability(new); + return -EINVAL; + } + + /* Subtract given access permissions */ + orig->access &= ~diff->access; + + /* Assign given perms to new capability */ + new->access = diff->access; + } + + /* Check size usage and split */ + if (orig->size) { + /* + * Split one can't have more, + * or make original redundant + */ + if (diff->size >= orig->size) { + free_capability(new); + return -EINVAL; + } + + /* Split one must be clean i.e. all unused */ + if (orig->size - orig->used < diff->size) { + free_capability(new); + return -EPERM; + } + + orig->size -= diff->size; + new->size = diff->size; + new->used = 0; + } + + /* Check range usage but don't split if requested */ + if (orig->start || orig->end) { + /* Range-like permissions can't be deduced */ + if (orig->start != new->start || + orig->end != new->end) { + free_capability(new); + return -EPERM; + } + } + + /* Copy other fields */ + new->type = orig->type; + new->resid = orig->resid; + new->owner = orig->owner; + + /* Add the new capability to the most private list */ + cap_list_insert(new, TASK_CAP_LIST(current)); + + return 0; +} + +/* + * Replicates an existing capability. This is for expanding + * capabilities to managed children. + * + * After replication, a duplicate capability exists in the + * system, but as it is not a quantity, this does not increase + * the capabilities of the caller in any way. + */ +int cap_replicate(l4id_t capid, struct capability *dupl) +{ + struct capability *new, *orig; + + /* Find original capability */ + orig = cap_find_byid(capid); + + /* Check that caller is owner */ + if (orig->owner != current->tid) + return -ENOCAP; + + /* Check that it is replicable */ + if (!(orig->access & CAP_REPLICABLE)) + return -ENOCAP; + + /* Quantitative types must not be replicable */ + if (cap_type(orig) == CAP_TYPE_QUANTITY) { + printk("Cont %d: FATAL: Capability (%d) " + "is quantitative but also replicable\n", + curcont->cid, orig->capid); + /* FIXME: Should rule this out as a CML2 requirement */ + BUG(); + } + + /* Replicate it */ + if (!(new = capability_create())) + return -ENOCAP; + + /* Copy all except capid & listptrs */ + new->resid = orig->resid; + new->owner = orig->owner; + new->type = orig->type; + new->access = orig->access; + new->start = orig->start; + new->end = orig->end; + new->size = orig->size; + new->used = orig->used; + + /* Add it to most private list */ + cap_list_insert(new, TASK_CAP_LIST(current)); + + /* Return new capability to user */ + memcpy(dupl, new, sizeof(*new)); + return 0; } /* * Read, manipulate capabilities. Currently only capability read support. */ -int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) +int sys_capability_control(unsigned int req, unsigned int flags, + l4id_t capid, l4id_t target, void *userbuf) { int err; @@ -124,8 +451,8 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) return err; switch(req) { - /* Return number of capabilities the thread has */ case CAP_CONTROL_NCAPS: + /* Return number of caps */ if (current->tid != current->pagerid) return -EPERM; @@ -138,68 +465,42 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) *((int *)userbuf) = TASK_CAP_LIST(current)->ncaps; break; - /* Return all capabilities as an array of capabilities */ - case CAP_CONTROL_READ: - err = read_task_capabilities(userbuf); + case CAP_CONTROL_READ: { + /* Return all capabilities as an array of capabilities */ + err = cap_read_all((struct capability *)userbuf); break; + } case CAP_CONTROL_SHARE: - err = capability_share(flags); + err = cap_share(capid, flags); break; + case CAP_CONTROL_GRANT: + err = cap_grant(flags, capid, target); + break; + case CAP_CONTROL_SPLIT: + err = cap_split(capid, (struct capability *)userbuf); + break; + case CAP_CONTROL_REPLICATE: + if ((err = check_access((unsigned long)userbuf, + sizeof(int), + MAP_USR_RW_FLAGS, 1)) < 0) + return err; + + err = cap_replicate(capid, (struct capability *)userbuf); + break; + case CAP_CONTROL_DEDUCE: + if ((err = check_access((unsigned long)userbuf, + sizeof(int), + MAP_USR_RW_FLAGS, 1)) < 0) + return err; + + err = cap_deduce(capid, (struct capability *)userbuf); + 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 diff --git a/src/generic/capability.c b/src/generic/capability.c index ff62991..194d2f9 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -38,7 +38,10 @@ struct capability *boot_capability_create(void) struct capability *capability_create(void) { - struct capability *cap = alloc_capability(); + struct capability *cap; + + if (!(cap = alloc_capability())) + return 0; capability_init(cap); @@ -124,9 +127,40 @@ struct capability *capability_find_by_rtype(struct ktcb *task, return 0; } +/* + * FIXME: Make these functions pass a match function to cap_find() + * and remove all duplication. Same goes for find_rtype. + */ +struct capability *cap_find_byid(l4id_t capid) +{ + struct capability *cap; + struct ktcb *task = current; + + /* Search task's own list */ + list_foreach_struct(cap, &task->cap_list.caps, list) + if (cap->capid == capid) + return cap; + + /* Search space list */ + list_foreach_struct(cap, &task->space->cap_list.caps, list) + if (cap->capid == capid) + return cap; + + /* Search container list */ + list_foreach_struct(cap, &task->container->cap_list.caps, list) + if (cap->capid == capid) + return cap; + + return 0; +} + typedef struct capability *(*cap_match_func_t) \ (struct capability *cap, void *match_args); +/* + * This is used by every system call to match each + * operation with a capability in a syscall-specific way. + */ struct capability *cap_find(struct ktcb *task, cap_match_func_t cap_match_func, void *match_args, unsigned int cap_type) { @@ -230,8 +264,14 @@ cap_match_capctrl(struct capability *cap, void *args_ptr) if (req == CAP_CONTROL_GRANT) if (!(cap->access & CAP_CAP_GRANT)) return 0; - if (req == CAP_CONTROL_MODIFY) - if (!(cap->access & CAP_CAP_MODIFY)) + if (req == CAP_CONTROL_REPLICATE) + if (!(cap->access & CAP_CAP_REPLICATE)) + return 0; + if (req == CAP_CONTROL_SPLIT) + if (!(cap->access & CAP_CAP_SPLIT)) + return 0; + if (req == CAP_CONTROL_DEDUCE) + if (!(cap->access & CAP_CAP_DEDUCE)) return 0; /* Now check the usual restype/resid pair */ @@ -759,7 +799,6 @@ 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: break; diff --git a/src/glue/arm/systable.c b/src/glue/arm/systable.c index 542251d..64a17a5 100644 --- a/src/glue/arm/systable.c +++ b/src/glue/arm/systable.c @@ -90,14 +90,16 @@ int arch_sys_map(syscall_context_t *regs) { return sys_map((unsigned long)regs->r0, (unsigned long)regs->r1, (unsigned long)regs->r2, (unsigned long)regs->r3, - (unsigned int)regs->r4); + (l4id_t)regs->r4); } int arch_sys_capability_control(syscall_context_t *regs) { return sys_capability_control((unsigned int)regs->r0, (unsigned int)regs->r1, - (void *)regs->r2); + (l4id_t)regs->r2, + (l4id_t)regs->r3, + (void *)regs->r4); } int arch_sys_container_control(syscall_context_t *regs)