From 83ce4280b048ac8b38bb22ffa8c97e8b98ebe4d5 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 24 Oct 2009 18:44:47 +0300 Subject: [PATCH] Some capability checking progress --- conts/test/include/capability.h | 6 +- conts/test/main.c | 3 +- conts/test/src/capability.c | 80 ++++++- conts/test/src/captest.c | 2 +- include/l4/generic/cap-types.h | 1 + src/api/SConscript | 2 +- src/api/{capability.c => cap.c} | 0 src/api/ipc.c | 4 + src/api/map.c | 17 +- src/api/thread.c | 3 + src/generic/capability.c | 369 ++++++++++++++++++++++++++++++-- 11 files changed, 447 insertions(+), 40 deletions(-) rename src/api/{capability.c => cap.c} (100%) diff --git a/conts/test/include/capability.h b/conts/test/include/capability.h index 84962e8..4beadac 100644 --- a/conts/test/include/capability.h +++ b/conts/test/include/capability.h @@ -5,10 +5,8 @@ #include #include -void print_capability(struct capability *cap); - -int read_pager_capabilities(); - +void capability_print(struct capability *cap); +int caps_read_all(); #endif /* __CAPABILITY_H__ */ diff --git a/conts/test/main.c b/conts/test/main.c index 34331bc..486baf8 100644 --- a/conts/test/main.c +++ b/conts/test/main.c @@ -1,5 +1,7 @@ /* * Main function for all tests + * + * Copyright (C) 2009 B Labs Ltd. */ #include #include @@ -9,7 +11,6 @@ int main(void) { - printf("%s: Container %s started\n", __CONTAINER__, __CONTAINER_NAME__); diff --git a/conts/test/src/capability.c b/conts/test/src/capability.c index 497956a..9ef805f 100644 --- a/conts/test/src/capability.c +++ b/conts/test/src/capability.c @@ -1,11 +1,80 @@ +/* + * Capability-related userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ #include #include #include 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; } diff --git a/conts/test/src/captest.c b/conts/test/src/captest.c index 10d9b51..b5faa8a 100644 --- a/conts/test/src/captest.c +++ b/conts/test/src/captest.c @@ -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 diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index c26d9f4..b2865a8 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -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) diff --git a/src/api/SConscript b/src/api/SConscript index 819acb3..d1426fe 100644 --- a/src/api/SConscript +++ b/src/api/SConscript @@ -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) diff --git a/src/api/capability.c b/src/api/cap.c similarity index 100% rename from src/api/capability.c rename to src/api/cap.c diff --git a/src/api/ipc.c b/src/api/ipc.c index 5bf6a28..e1dad5a 100644 --- a/src/api/ipc.c +++ b/src/api/ipc.c @@ -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); diff --git a/src/api/map.c b/src/api/map.c index 8c19775..e20da71 100644 --- a/src/api/map.c +++ b/src/api/map.c @@ -10,22 +10,17 @@ #include 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; diff --git a/src/api/thread.c b/src/api/thread.c index ea2fb4d..0154459 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -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); diff --git a/src/generic/capability.c b/src/generic/capability.c index b6c2f34..93dfaa8 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -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: *