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 */