From dc03c7b1305f6b76eb524cd73db9a608478203e2 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sun, 8 Nov 2009 14:15:33 +0200 Subject: [PATCH] Implemented a protocol between client and pager for requesting caps. In posix, test0 makes inter-space ipc for testing extended ipc. This correctly fails when only the cap to ipc to pager is given to all tasks in the container. In order to overcome this problem, the tasks who fork for doing ipc to each other make a request to the pager to get capabilities to do so. Pager finds its own widened ipc capability over the container, replicates it, validates and reduces it to desired boundaries (i.e. just ipc betw. two spaces) and grants it as IMMUTABLE to requesting tasks. This protocol may be useful in implementing a client/server capability request relationship. Code builds but untested. --- conts/libl4/include/l4lib/capability.h | 80 +++++ conts/libl4/include/l4lib/ipcdefs.h | 1 + conts/posix/mm0/include/capability.h | 77 +--- conts/posix/mm0/include/init.h | 1 + conts/posix/mm0/main.c | 7 +- conts/posix/mm0/mm/capability.c | 470 ++++++++++++++++++++++++- conts/posix/mm0/mm/init.c | 375 -------------------- conts/posix/mm0/mm/task.c | 2 +- conts/posix/test0/src/ipctest.c | 45 +++ include/l4/api/capability.h | 3 +- include/l4/generic/cap-types.h | 4 + include/l4/generic/capability.h | 2 +- 12 files changed, 616 insertions(+), 451 deletions(-) create mode 100644 conts/libl4/include/l4lib/capability.h diff --git a/conts/libl4/include/l4lib/capability.h b/conts/libl4/include/l4lib/capability.h new file mode 100644 index 0000000..13571e2 --- /dev/null +++ b/conts/libl4/include/l4lib/capability.h @@ -0,0 +1,80 @@ +/* + * Capability-related management. + * + * Copyright (C) 2009 Bahadir Balban + */ +#ifndef __LIBL4_CAPABILITY_H__ +#define __LIBL4_CAPABILITY_H__ + +#include +#include + +struct cap_list { + int ncaps; + struct link caps; +}; + +struct capability { + struct link list; + + /* Capability identifiers */ + l4id_t capid; /* Unique capability ID */ + l4id_t owner; /* Capability owner ID */ + l4id_t resid; /* Targeted resource ID */ + unsigned int type; /* Capability and target resource type */ + + /* Capability limits/permissions */ + u32 access; /* Permitted operations */ + + /* Limits on the resource */ + unsigned long start; /* Resource start value */ + unsigned long end; /* Resource end value */ + unsigned long size; /* Resource size */ + + unsigned long used; /* Resource used size */ +}; + + +static inline void cap_list_init(struct cap_list *clist) +{ + clist->ncaps = 0; + link_init(&clist->caps); +} + +static inline void cap_list_insert(struct capability *cap, + struct cap_list *clist) +{ + list_insert(&cap->list, &clist->caps); + 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); +} + + +#endif /* __LIBL4_CAPABILITY_H__ */ diff --git a/conts/libl4/include/l4lib/ipcdefs.h b/conts/libl4/include/l4lib/ipcdefs.h index 31537d1..41e2942 100644 --- a/conts/libl4/include/l4lib/ipcdefs.h +++ b/conts/libl4/include/l4lib/ipcdefs.h @@ -63,6 +63,7 @@ #define L4_IPC_TAG_NOTIFY_EXIT 47 /* Pager notifies vfs of process exit */ #define L4_IPC_TAG_PAGER_OPEN_BYPATH 48 /* Pager opens a vfs file by pathname */ +#define L4_REQUEST_CAPABILITY 50 /* Request a capability from pager */ extern l4id_t pagerid; #endif /* __IPCDEFS_H__ */ diff --git a/conts/posix/mm0/include/capability.h b/conts/posix/mm0/include/capability.h index 49517f5..d9db553 100644 --- a/conts/posix/mm0/include/capability.h +++ b/conts/posix/mm0/include/capability.h @@ -6,76 +6,8 @@ #ifndef __MM0_CAPABILITY_H__ #define __MM0_CAPABILITY_H__ -#include -#include - -struct cap_list { - int ncaps; - struct link caps; -}; - -struct capability { - struct link list; - - /* Capability identifiers */ - l4id_t capid; /* Unique capability ID */ - l4id_t resid; /* Targeted resource ID */ - l4id_t owner; /* Capability owner ID */ - unsigned int type; /* Capability and target resource type */ - - /* Capability limits/permissions */ - u32 access; /* Permitted operations */ - - /* Limits on the resource */ - unsigned long start; /* Resource start value */ - unsigned long end; /* Resource end value */ - unsigned long size; /* Resource size */ - - unsigned long used; /* Resource used size */ -}; - - -static inline void cap_list_init(struct cap_list *clist) -{ - clist->ncaps = 0; - link_init(&clist->caps); -} - -static inline void cap_list_insert(struct capability *cap, - struct cap_list *clist) -{ - list_insert(&cap->list, &clist->caps); - 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); -} - +#include +#include extern struct cap_list capability_list; @@ -83,4 +15,9 @@ struct initdata; int read_pager_capabilities(); void copy_boot_capabilities(); +int sys_request_cap(struct tcb *sender, struct capability *c); + +void cap_print(struct capability *cap); +void cap_list_print(struct cap_list *cap_list); +void setup_caps(); #endif /* __MM0_CAPABILITY_H__ */ diff --git a/conts/posix/mm0/include/init.h b/conts/posix/mm0/include/init.h index 121a83f..5e372ae 100644 --- a/conts/posix/mm0/include/init.h +++ b/conts/posix/mm0/include/init.h @@ -29,6 +29,7 @@ extern struct initdata initdata; void init(void); +void copy_boot_capabilities(int ncaps); /* TODO: Remove this stuff from here. */ int init_devzero(void); struct vm_file *get_devzero(void); diff --git a/conts/posix/mm0/main.c b/conts/posix/mm0/main.c index 3f5023e..4bd042e 100644 --- a/conts/posix/mm0/main.c +++ b/conts/posix/mm0/main.c @@ -22,7 +22,7 @@ #include #include #include - +#include /* Receives all registers and origies back */ int ipc_test_full_sync(l4id_t senderid) @@ -88,7 +88,10 @@ void handle_requests(void) ret = 0; break; } - + case L4_REQUEST_CAPABILITY: { + ret = sys_request_cap(sender, (struct capability *)mr[0]); + break; + } case L4_IPC_TAG_SHMGET: { ret = sys_shmget((key_t)mr[0], (int)mr[1], (int)mr[2]); break; diff --git a/conts/posix/mm0/mm/capability.c b/conts/posix/mm0/mm/capability.c index ee5b172..ebd6c77 100644 --- a/conts/posix/mm0/mm/capability.c +++ b/conts/posix/mm0/mm/capability.c @@ -5,10 +5,478 @@ */ #include #include -#include +#include #include #include +#include +#include #include #include /* TODO: Move this to API */ +#include #include +/* Capability descriptor list */ +struct cap_list capability_list; + +__initdata static struct capability *caparray; +__initdata static int total_caps = 0; + +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); + printf("Capability owner id:\t\t%d\n",cap->owner); + + switch (cap_type(cap)) { + case CAP_TYPE_TCTRL: + printf("Capability type:\t\t%s\n", "Thread Control"); + break; + case CAP_TYPE_EXREGS: + printf("Capability type:\t\t%s\n", "Exchange Registers"); + break; + case CAP_TYPE_MAP_PHYSMEM: + printf("Capability type:\t\t%s\n", "Map/Physmem"); + break; + case CAP_TYPE_MAP_VIRTMEM: + printf("Capability type:\t\t%s\n", "Map/Virtmem"); + break; + + case CAP_TYPE_IPC: + printf("Capability type:\t\t%s\n", "Ipc"); + break; + case CAP_TYPE_UMUTEX: + printf("Capability type:\t\t%s\n", "Mutex"); + break; + case CAP_TYPE_QUANTITY: + printf("Capability type:\t\t%s\n", "Quantitative"); + break; + default: + printf("Capability type:\t\t%s\n", "Unknown"); + break; + } + + switch (cap_rtype(cap)) { + case CAP_RTYPE_THREAD: + printf("Capability resource type:\t%s\n", "Thread"); + break; + case CAP_RTYPE_SPACE: + printf("Capability resource type:\t%s\n", "Space"); + break; + case CAP_RTYPE_CONTAINER: + printf("Capability resource type:\t%s\n", "Container"); + break; + case CAP_RTYPE_THREADPOOL: + printf("Capability resource type:\t%s\n", "Thread Pool"); + break; + case CAP_RTYPE_SPACEPOOL: + printf("Capability resource type:\t%s\n", "Space Pool"); + break; + case CAP_RTYPE_MUTEXPOOL: + printf("Capability resource type:\t%s\n", "Mutex Pool"); + break; + case CAP_RTYPE_MAPPOOL: + printf("Capability resource type:\t%s\n", "Map Pool (PMDS)"); + break; + case CAP_RTYPE_CPUPOOL: + printf("Capability resource type:\t%s\n", "Cpu Pool"); + break; + case CAP_RTYPE_CAPPOOL: + printf("Capability resource type:\t%s\n", "Capability Pool"); + break; + default: + printf("Capability resource type:\t%s\n", "Unknown"); + break; + } + printf("\n"); +} + +void cap_list_print(struct cap_list *cap_list) +{ + struct capability *cap; + printf("Capabilities\n" + "~~~~~~~~~~~~\n"); + + list_foreach_struct(cap, &cap_list->caps, list) + cap_print(cap); + + printf("\n"); +} + +/* + * Replicate, deduce and grant to children the capability to + * talk to us only. + * + * We are effectively creating an ipc capability from what we already + * own, and the new one has a reduced privilege in terms of the + * targetable resource. + * + * We are replicating our capability to talk to our complete container + * into a capability to only talk to our current space. Our space is a + * reduced target, since it is a subset contained in our container. + */ +int setup_children_caps(int total_caps, struct cap_list *cap_list) +{ + struct capability *ipc_cap, *cap; + struct task_ids ids; + int err; + + l4_getid(&ids); + + cap_list_print(cap_list); + + /* Find out our own ipc capability on our own container */ + list_foreach_struct(cap, &cap_list->caps, list) { + if (cap_type(cap) == CAP_TYPE_IPC && + cap_rtype(cap) == CAP_RTYPE_CONTAINER && + cap->resid == __cid(ids.tid)) + goto found; + } + printf("cont%d: %s: FATAL: Could not find ipc " + "capability to own container.\n", + __cid(ids.tid), __FUNCTION__); + BUG(); + +found: + /* Create a new capability */ + BUG_ON(!(ipc_cap = kzalloc(sizeof(*ipc_cap)))); + + /* Copy it over to new ipc cap buffer */ + memcpy(ipc_cap, cap, sizeof (*cap)); + + /* Replicate the ipc capability, giving original as reference */ + if ((err = l4_capability_control(CAP_CONTROL_REPLICATE, + 0, 0, 0, ipc_cap)) < 0) { + printf("l4_capability_control() replication of " + "ipc capability failed.\n Could not " + "complete CAP_CONTROL_REPLICATE request on cap (%d), " + "err = %d.\n", ipc_cap->capid, err); + BUG(); + } + + /* Add it to list */ + cap_list_insert(ipc_cap, cap_list); + cap_list_print(cap_list); + + /* + * The returned capability is a replica. + * + * Now deduce it such that it applies to talking only to us, + * instead of to the whole container as original. + */ + cap_set_rtype(ipc_cap, CAP_RTYPE_SPACE); + ipc_cap->resid = ids.spid; /* This space is target resource */ + if ((err = l4_capability_control(CAP_CONTROL_DEDUCE, + 0, 0, 0, ipc_cap)) < 0) { + printf("l4_capability_control() deduction of " + "ipc capability failed.\n Could not " + "complete CAP_CONTROL_DEDUCE request on cap (%d), " + "err = %d.\n", ipc_cap->capid, err); + BUG(); + } + + cap_list_print(cap_list); + + /* + * Share it with our container. + * + * This effectively enables all threads/spaces in this container + * to communicate to us only, and be able to do nothing else. + */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE, CAP_SHARE_SINGLE, + ipc_cap->capid, 0, 0)) < 0) { + printf("l4_capability_control() sharing of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_SHARE request.\n"); + BUG(); + } + cap_list_print(cap_list); + + return 0; +} + +/* Copy all init-memory allocated capabilities */ +void copy_boot_capabilities(int ncaps) +{ + struct capability *cap; + + capability_list.ncaps = 0; + link_init(&capability_list.caps); + + for (int i = 0; i < ncaps; i++) { + cap = kzalloc(sizeof(struct capability)); + + /* This copies kernel-allocated unique cap id as well */ + memcpy(cap, &caparray[i], sizeof(struct capability)); + + /* Initialize capability list */ + link_init(&cap->list); + + /* Add capability to global cap list */ + cap_list_insert(cap, &capability_list); + } +} + +int cap_read_all() +{ + int ncaps; + int err; + struct capability *cap; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, 0, 0, &ncaps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + BUG(); + } + total_caps = ncaps; + + /* Allocate array of caps from boot memory */ + caparray = alloc_bootmem(sizeof(struct capability) * ncaps, 0); + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, 0, 0, caparray)) < 0) { + printf("l4_capability_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ_CAPS request.\n"); + BUG(); + } + + /* Copy them to real allocated structures */ + copy_boot_capabilities(ncaps); + + memset(&cont_mem_regions, 0, sizeof(cont_mem_regions)); + + /* Set up pointers to important capabilities */ + list_foreach_struct(cap, &capability_list.caps, list) { + /* Physical memory bank */ + if (cap_type(cap) == CAP_TYPE_MAP_PHYSMEM) + cont_mem_regions.physmem = cap; + + /* Virtual regions */ + if (cap_type(cap) == CAP_TYPE_MAP_VIRTMEM) { + + /* Pager address region (get from linker-defined) */ + if (__pfn_to_addr(cap->start) + == (unsigned long)virtual_base) + cont_mem_regions.pager = cap; + + /* UTCB address region */ + else if (UTCB_REGION_START == + __pfn_to_addr(cap->start)) { + if (UTCB_REGION_END != + __pfn_to_addr(cap->end)) { + printf("FATAL: Region designated " + "for UTCB allocation does not " + "match on start/end marks"); + BUG(); + } + + if (!(cap->access & CAP_MAP_UTCB_BIT)) { + printf("FATAL: Region designated " + "for UTCB allocation does not " + "have UTCB map permissions"); + BUG(); + } + cont_mem_regions.utcb = cap; + } + + /* Shared memory disjoint region */ + else if (SHMEM_REGION_START == + __pfn_to_addr(cap->start)) { + if (SHMEM_REGION_END != + __pfn_to_addr(cap->end)) { + printf("FATAL: Region designated " + "for SHM allocation does not " + "match on start/end marks"); + BUG(); + } + + cont_mem_regions.shmem = cap; + } + + /* Task memory region */ + else if (TASK_REGION_START == + __pfn_to_addr(cap->start)) { + if (TASK_REGION_END != + __pfn_to_addr(cap->end)) { + printf("FATAL: Region designated " + "for Task address space does" + "not match on start/end mark."); + BUG(); + } + cont_mem_regions.task = cap; + } + } + } + + if (!cont_mem_regions.task || + !cont_mem_regions.shmem || + !cont_mem_regions.utcb || + !cont_mem_regions.physmem || + !cont_mem_regions.pager) { + printf("%s: Error, pager does not have one of the required" + "mem capabilities defined. (TASK, SHM, PHYSMEM, UTCB)\n", + __TASKNAME__); + printf("%p, %p, %p, %p, %p\n", cont_mem_regions.task, + cont_mem_regions.shmem, cont_mem_regions.utcb, + cont_mem_regions.physmem, cont_mem_regions.pager); + BUG(); + } + + return 0; +} + +void setup_caps() +{ + cap_read_all(); + setup_children_caps(total_caps, &capability_list); +} + +/* + * Find our own, widened replicable capability of same type as given, + * replicate, reduce and grant as described with given parameters. + * Assumes parameters have already been validated and security-checked. + */ +int cap_find_reduce_grant(struct capability *cap) +{ + struct capability *possessed; + struct capability new_cap; + int err; + + list_foreach_struct(possessed, &capability_list.caps, list) { + /* + * For now, we only match types, we don't check + * whether possessed one is superior enough to + * produce the requested cap. + */ + if (cap_type(possessed) == cap_type(cap)) + goto found; + } + return -ENOCAP; + +found: + /* Copy possessed one to new one's buffer */ + memcpy(&new_cap, possessed, sizeof(*possessed)); + + /* Replicate the possessed capability, giving original as reference */ + if ((err = l4_capability_control(CAP_CONTROL_REPLICATE, + 0, 0, 0, &new_cap)) < 0) { + printf("l4_capability_control() replication of " + "capability failed.\n Could not " + "complete CAP_CONTROL_REPLICATE request on cap (%d), " + "err = %d.\n", new_cap.capid, err); + return err; + } + + /* + * The returned capability is a replica. + * + * We don't add the newly created one to our own internal + * list because we will grant it shortly and lose its + * possession + * + * Now deduce it such that it looks like the one requested. + * Note, we assume the request had been validated before. + */ + new_cap.owner = cap->owner; + new_cap.resid = cap->resid; + new_cap.type = cap->type; + new_cap.access = cap->access; + new_cap.start = cap->start; + new_cap.end = cap->end; + new_cap.size = cap->size; + new_cap.used = cap->used; + + /* + * Make sure it is transferable, + * since we will need to grant it soon + */ + new_cap.access |= CAP_TRANSFERABLE; + + if ((err = l4_capability_control(CAP_CONTROL_DEDUCE, + 0, 0, 0, &new_cap)) < 0) { + printf("l4_capability_control() deduction of " + "ipc capability failed.\n Could not " + "complete CAP_CONTROL_DEDUCE request on cap (%d), " + "err = %d.\n", new_cap.capid, err); + return err; + } + + /* + * Grant it to given owner. + * + * This effectively enables the owner to have all operations defined + * in the capability. However, we use a flag to make the capability + * immutable as we grant it. (We wouldn't be able to grant it if it + * had no grant permission originally. We remove it as we grant it) + */ + if ((err = l4_capability_control(CAP_CONTROL_GRANT, + CAP_GRANT_SINGLE | CAP_GRANT_IMMUTABLE, + 0, 0, &new_cap)) < 0) { + printf("l4_capability_control() granting of " + "capability (%d) failed.\n Could not " + "complete CAP_CONTROL_GRANT request.\n", + new_cap.capid); + return err; + } + return 0; +} + +/* + * A task that we manage requests a capability to do an operation + * from us, such as the capability to do a particular ipc to a + * particular thread. We consider the request and give the + * capability if it is appropriate. This currently supports only + * ipc. + */ +int sys_request_cap(struct tcb *sender, struct capability *cap) +{ + struct tcb *target; + int err; + + /* Only support IPC requests for now */ + if (cap_type(cap) != CAP_TYPE_IPC) + return -EPERM; + + /* Validate rest of the fields */ + if (cap->start || cap->end || cap->used || cap->size) + return -EINVAL; + + if (cap_generic_perms(cap) != CAP_IMMUTABLE) + return -EPERM; + + /* Find out who the task wants to ipc */ + switch (cap_rtype(cap)) { + /* Is it a thread? */ + case CAP_RTYPE_THREAD: + /* Find the thread */ + if (!(target = find_task(cap->resid))) + return -ESRCH; + + /* Requester must be the owner */ + if (cap->owner != sender->tid) + return -EPERM; + + /* + * It is a thread that we are managing, nothing + * special requested here, just grant it + */ + if ((err = cap_find_reduce_grant(cap)) < 0) + return err; + break; + case CAP_RTYPE_SPACE: + /* Space requests not allowed */ + return -EPERM; + break; + case CAP_RTYPE_CONTAINER: + /* Container requests not allowed */ + return -EPERM; + break; + } + + return 0; +} + diff --git a/conts/posix/mm0/mm/init.c b/conts/posix/mm0/mm/init.c index f706cdf..bd13c1b 100644 --- a/conts/posix/mm0/mm/init.c +++ b/conts/posix/mm0/mm/init.c @@ -43,16 +43,9 @@ struct memdesc physmem; /* Initial, primitive memory descriptor */ struct membank membank[1]; /* The memory bank */ struct page *page_array; /* The physical page array based on mem bank */ - -/* Capability descriptor list */ -struct cap_list capability_list; - /* Memory region capabilities */ struct container_memory_regions cont_mem_regions; -__initdata static struct capability *caparray; -__initdata static int total_caps = 0; - void print_pfn_range(int pfn, int size) { unsigned int addr = pfn << PAGE_BITS; @@ -60,7 +53,6 @@ void print_pfn_range(int pfn, int size) printf("Used: 0x%x - 0x%x\n", addr, end); } - /* * This sets up the mm0 task struct and memory environment but omits * bits that are already done such as creating a new thread, setting @@ -158,373 +150,6 @@ int pager_setup_task(void) return 0; } -/* Copy all init-memory allocated capabilities */ -void copy_boot_capabilities(int ncaps) -{ - struct capability *cap; - - capability_list.ncaps = 0; - link_init(&capability_list.caps); - - for (int i = 0; i < total_caps; i++) { - cap = kzalloc(sizeof(struct capability)); - - /* This copies kernel-allocated unique cap id as well */ - memcpy(cap, &caparray[i], sizeof(struct capability)); - - /* Initialize capability list */ - link_init(&cap->list); - - /* Add capability to global cap list */ - cap_list_insert(cap, &capability_list); - } -} - -#if 0 -/* - * 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; - - /* Replicate 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; -} -#endif - -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); - printf("Capability owner id:\t\t%d\n",cap->owner); - - switch (cap_type(cap)) { - case CAP_TYPE_TCTRL: - printf("Capability type:\t\t%s\n", "Thread Control"); - break; - case CAP_TYPE_EXREGS: - printf("Capability type:\t\t%s\n", "Exchange Registers"); - break; - case CAP_TYPE_MAP_PHYSMEM: - printf("Capability type:\t\t%s\n", "Map/Physmem"); - break; - case CAP_TYPE_MAP_VIRTMEM: - printf("Capability type:\t\t%s\n", "Map/Virtmem"); - break; - - case CAP_TYPE_IPC: - printf("Capability type:\t\t%s\n", "Ipc"); - break; - case CAP_TYPE_UMUTEX: - printf("Capability type:\t\t%s\n", "Mutex"); - break; - case CAP_TYPE_QUANTITY: - printf("Capability type:\t\t%s\n", "Quantitative"); - break; - default: - printf("Capability type:\t\t%s\n", "Unknown"); - break; - } - - switch (cap_rtype(cap)) { - case CAP_RTYPE_THREAD: - printf("Capability resource type:\t%s\n", "Thread"); - break; - case CAP_RTYPE_SPACE: - printf("Capability resource type:\t%s\n", "Space"); - break; - case CAP_RTYPE_CONTAINER: - printf("Capability resource type:\t%s\n", "Container"); - break; - case CAP_RTYPE_THREADPOOL: - printf("Capability resource type:\t%s\n", "Thread Pool"); - break; - case CAP_RTYPE_SPACEPOOL: - printf("Capability resource type:\t%s\n", "Space Pool"); - break; - case CAP_RTYPE_MUTEXPOOL: - printf("Capability resource type:\t%s\n", "Mutex Pool"); - break; - case CAP_RTYPE_MAPPOOL: - printf("Capability resource type:\t%s\n", "Map Pool (PMDS)"); - break; - case CAP_RTYPE_CPUPOOL: - printf("Capability resource type:\t%s\n", "Cpu Pool"); - break; - case CAP_RTYPE_CAPPOOL: - printf("Capability resource type:\t%s\n", "Capability Pool"); - break; - default: - printf("Capability resource type:\t%s\n", "Unknown"); - break; - } - printf("\n"); -} - -void cap_list_print(struct cap_list *cap_list) -{ - struct capability *cap; - printf("Capabilities\n" - "~~~~~~~~~~~~\n"); - - list_foreach_struct(cap, &cap_list->caps, list) - cap_print(cap); - - printf("\n"); -} -/* - * Replicate, deduce and grant to children the capability to - * talk to us only. - * - * We are effectively creating an ipc capability from what we already - * own, and the new one has a reduced privilege in terms of the - * targetable resource. - * - * We are replicating our capability to talk to our complete container - * into a capability to only talk to our current space. Our space is a - * reduced target, since it is a subset contained in our container. - */ -int setup_children_caps(int total_caps, struct cap_list *cap_list) -{ - struct capability *ipc_cap, *cap; - struct task_ids ids; - int err; - - l4_getid(&ids); - - cap_list_print(cap_list); - - /* Find out our own ipc capability on our own container */ - list_foreach_struct(cap, &cap_list->caps, list) { - if (cap_type(cap) == CAP_TYPE_IPC && - cap_rtype(cap) == CAP_RTYPE_CONTAINER && - cap->resid == __cid(ids.tid)) - goto found; - } - printf("cont%d: %s: FATAL: Could not find ipc " - "capability to own container.\n", - __cid(ids.tid), __FUNCTION__); - BUG(); - -found: - /* Create a new capability */ - BUG_ON(!(ipc_cap = kzalloc(sizeof(*ipc_cap)))); - - /* Copy it over to new ipc cap buffer */ - memcpy(ipc_cap, cap, sizeof (*cap)); - - /* Replicate the ipc capability, giving original as reference */ - if ((err = l4_capability_control(CAP_CONTROL_REPLICATE, - 0, 0, 0, ipc_cap)) < 0) { - printf("l4_capability_control() replication of " - "ipc capability failed.\n Could not " - "complete CAP_CONTROL_REPLICATE request on cap (%d), " - "err = %d.\n", ipc_cap->capid, err); - BUG(); - } - - /* Add it to list */ - cap_list_insert(ipc_cap, cap_list); - cap_list_print(cap_list); - - /* - * The returned capability is a replica. - * - * Now deduce it such that it applies to talking only to us, - * instead of to the whole container as original. - */ - cap_set_rtype(ipc_cap, CAP_RTYPE_SPACE); - ipc_cap->resid = ids.spid; /* This space is target resource */ - if ((err = l4_capability_control(CAP_CONTROL_DEDUCE, - 0, 0, 0, ipc_cap)) < 0) { - printf("l4_capability_control() deduction of " - "ipc capability failed.\n Could not " - "complete CAP_CONTROL_DEDUCE request on cap (%d), " - "err = %d.\n", ipc_cap->capid, err); - BUG(); - } - - cap_list_print(cap_list); - - /* - * Share it with our container. - * - * This effectively enables all threads/spaces in this container - * to communicate to us only, and be able to do nothing else. - */ - if ((err = l4_capability_control(CAP_CONTROL_SHARE, CAP_SHARE_SINGLE, - ipc_cap->capid, 0, 0)) < 0) { - printf("l4_capability_control() sharing of " - "capabilities failed.\n Could not " - "complete CAP_CONTROL_SHARE request.\n"); - BUG(); - } - cap_list_print(cap_list); - - return 0; -} - -int pager_read_caps() -{ - int ncaps; - int err; - struct capability *cap; - - /* Read number of capabilities */ - if ((err = l4_capability_control(CAP_CONTROL_NCAPS, - 0, 0, 0, &ncaps)) < 0) { - printf("l4_capability_control() reading # of" - " capabilities failed.\n Could not " - "complete CAP_CONTROL_NCAPS request.\n"); - BUG(); - } - total_caps = ncaps; - - /* Allocate array of caps from boot memory */ - caparray = alloc_bootmem(sizeof(struct capability) * ncaps, 0); - - /* Read all capabilities */ - if ((err = l4_capability_control(CAP_CONTROL_READ, - 0, 0, 0, caparray)) < 0) { - printf("l4_capability_control() reading of " - "capabilities failed.\n Could not " - "complete CAP_CONTROL_READ_CAPS request.\n"); - BUG(); - } - - /* Copy them to real allocated structures */ - copy_boot_capabilities(ncaps); - - memset(&cont_mem_regions, 0, sizeof(cont_mem_regions)); - - /* Set up pointers to important capabilities */ - list_foreach_struct(cap, &capability_list.caps, list) { - /* Physical memory bank */ - if (cap_type(cap) == CAP_TYPE_MAP_PHYSMEM) - cont_mem_regions.physmem = cap; - - /* Virtual regions */ - if (cap_type(cap) == CAP_TYPE_MAP_VIRTMEM) { - - /* Pager address region (get from linker-defined) */ - if (__pfn_to_addr(cap->start) - == (unsigned long)virtual_base) - cont_mem_regions.pager = cap; - - /* UTCB address region */ - else if (UTCB_REGION_START == - __pfn_to_addr(cap->start)) { - if (UTCB_REGION_END != - __pfn_to_addr(cap->end)) { - printf("FATAL: Region designated " - "for UTCB allocation does not " - "match on start/end marks"); - BUG(); - } - - if (!(cap->access & CAP_MAP_UTCB_BIT)) { - printf("FATAL: Region designated " - "for UTCB allocation does not " - "have UTCB map permissions"); - BUG(); - } - cont_mem_regions.utcb = cap; - } - - /* Shared memory disjoint region */ - else if (SHMEM_REGION_START == - __pfn_to_addr(cap->start)) { - if (SHMEM_REGION_END != - __pfn_to_addr(cap->end)) { - printf("FATAL: Region designated " - "for SHM allocation does not " - "match on start/end marks"); - BUG(); - } - - cont_mem_regions.shmem = cap; - } - - /* Task memory region */ - else if (TASK_REGION_START == - __pfn_to_addr(cap->start)) { - if (TASK_REGION_END != - __pfn_to_addr(cap->end)) { - printf("FATAL: Region designated " - "for Task address space does" - "not match on start/end mark."); - BUG(); - } - cont_mem_regions.task = cap; - } - } - } - - if (!cont_mem_regions.task || - !cont_mem_regions.shmem || - !cont_mem_regions.utcb || - !cont_mem_regions.physmem || - !cont_mem_regions.pager) { - printf("%s: Error, pager does not have one of the required" - "mem capabilities defined. (TASK, SHM, PHYSMEM, UTCB)\n", - __TASKNAME__); - printf("%p, %p, %p, %p, %p\n", cont_mem_regions.task, - cont_mem_regions.shmem, cont_mem_regions.utcb, - cont_mem_regions.physmem, cont_mem_regions.pager); - BUG(); - } - - return 0; -} - -void setup_caps() -{ - pager_read_caps(); - setup_children_caps(total_caps, &capability_list); -} - /* * Copy all necessary data from initmem to real memory, * release initdata and any init memory used diff --git a/conts/posix/mm0/mm/task.c b/conts/posix/mm0/mm/task.c index 41e643f..2e877f7 100644 --- a/conts/posix/mm0/mm/task.c +++ b/conts/posix/mm0/mm/task.c @@ -529,7 +529,7 @@ int task_map_stack(struct vm_file *f, struct exec_file_desc *efd, * Stack contains: args, environment, argc integer, * 2 Null integers as terminators. * - * It needs to be 8-byte aligned also. + * It also needs to be 8-byte aligned. */ stack_used = align_up(args->size + env->size + sizeof(int) * 3 + 8, 8); task->stack_end = __pfn_to_addr(cont_mem_regions.task->end); diff --git a/conts/posix/test0/src/ipctest.c b/conts/posix/test0/src/ipctest.c index 7c0e988..cb09614 100644 --- a/conts/posix/test0/src/ipctest.c +++ b/conts/posix/test0/src/ipctest.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include /* * Full ipc test. Sends/receives full utcb, done with the pager. @@ -45,16 +48,39 @@ void ipc_full_test(void) printf("FULL IPC TEST: -- FAILED --\n"); } +int cap_request_pager(struct capability *cap) +{ + int err; + + write_mr(L4SYS_ARG0, (u32)cap); + + if ((err = l4_sendrecv(pagerid, pagerid, + L4_REQUEST_CAPABILITY)) < 0) { + printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err); + return err; + } + + /* Check if syscall itself was successful */ + if ((err = l4_get_retval()) < 0) { + printf("%s: Error: %d\n", __FUNCTION__, err); + return err; + } + return err; +} + /* * This is an extended ipc test that is done between 2 tasks that fork. */ void ipc_extended_test(void) { pid_t child, parent; + struct capability cap; void *base; char *ipcbuf; int err; + memset(&cap, 0, sizeof(cap)); + /* Get parent pid */ parent = getpid(); @@ -71,6 +97,25 @@ void ipc_extended_test(void) /* This test makes this assumption */ BUG_ON(L4_IPC_EXTENDED_MAX_SIZE > PAGE_SIZE); + /* + * Request capability to ipc to each other from pager + * (Actually only the sender needs it) + */ + if (child) { + cap.owner = parent; + cap.resid = child; + } else { + cap.owner = child; + cap.resid = parent; + } + cap.type = CAP_TYPE_IPC | CAP_RTYPE_THREAD; + cap.access = CAP_IPC_EXTENDED; + if ((err = cap_request_pager(&cap)) < 0) { + printf("Ipc capability request failed. " + "err = %d\n", err); + goto out_err; + } + /* * Both child and parent gets 2 pages * of privately mapped anonymous memory diff --git a/include/l4/api/capability.h b/include/l4/api/capability.h index 9c83eda..82b1ddb 100644 --- a/include/l4/api/capability.h +++ b/include/l4/api/capability.h @@ -19,9 +19,10 @@ #define CAP_SHARE_SINGLE 0x00000001 #define CAP_SHARE_ALL 0x00000002 -#define CAP_GRANT_MASK 0x00000003 +#define CAP_GRANT_MASK 0x0000000F #define CAP_GRANT_SINGLE 0x00000001 #define CAP_GRANT_ALL 0x00000002 +#define CAP_GRANT_IMMUTABLE 0x00000004 /* Task's primary capability list */ #define TASK_CAP_LIST(task) \ diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index 5df4e33..3fe411e 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -48,6 +48,10 @@ #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 */ +#define CAP_GENERIC_MASK 0xF0000000 +#define CAP_IMMUTABLE 0 +#define cap_generic_perms(c) \ + ((c)->access & CAP_GENERIC_MASK) /* Thread control capability */ #define CAP_TCTRL_CREATE (1 << 0) diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index af22ddd..cee582e 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -59,8 +59,8 @@ struct capability { /* Capability identifiers */ l4id_t capid; /* Unique capability ID */ - l4id_t resid; /* Targeted resource ID */ l4id_t owner; /* Capability owner ID */ + l4id_t resid; /* Targeted resource ID */ unsigned int type; /* Capability and target resource type */ /* Capability limits/permissions */