diff --git a/conts/libl4/include/l4lib/arch-arm/syscalls.h b/conts/libl4/include/l4lib/arch-arm/syscalls.h index de08dec..2023471 100644 --- a/conts/libl4/include/l4lib/arch-arm/syscalls.h +++ b/conts/libl4/include/l4lib/arch-arm/syscalls.h @@ -42,7 +42,8 @@ int l4_ipc(l4id_t to, l4id_t from, u32 flags); typedef int (*__l4_capability_control_t)(unsigned int req, unsigned int flags, void *buf); extern __l4_capability_control_t __l4_capability_control; -int l4_capability_control(unsigned int req, unsigned int flags, void *buf); +int l4_capability_control(unsigned int req, unsigned int flags, + l4id_t capid, l4id_t tid, void *buf); typedef int (*__l4_map_t)(void *phys, void *virt, u32 npages, u32 flags, l4id_t tid); diff --git a/conts/libl4/src/arm/syscalls.S b/conts/libl4/src/arm/syscalls.S index e15a695..863e93d 100644 --- a/conts/libl4/src/arm/syscalls.S +++ b/conts/libl4/src/arm/syscalls.S @@ -37,20 +37,6 @@ BEGIN_PROC(l4_getid) ldr pc, [r12] @ Return. END_PROC(l4_getid) -/* - * Reads/manipulates capabilities of a thread, particularly a pager. - * @r0 = request type, @r1 = request flags, @r2 = io buffer ptr - */ -BEGIN_PROC(l4_capability_control) - ldr r12, =__l4_capability_control - ldr pc, [r12] @ Jump into the SWI - /* - * The LR_USR points at the return address of this function. The system - * call return path directly jumps to LR_USR so we don't even need a - * return instruction here. - */ -END_PROC(l4_capability_control) - /* * For clone() we need special assembler handling * Same signature as ipc(): @r0 = to, @r1 = from @r2 = flags @@ -124,6 +110,20 @@ BEGIN_PROC(l4_map) ldmfd sp!, {r4, pc} END_PROC(l4_map) +/* + * Reads/manipulates capabilities of a thread, particularly a pager. + * @r0 = request type, @r1 = request flags, + * @r2 = capid, @r3 = target thread id, @r4 = io buffer ptr + */ +BEGIN_PROC(l4_capability_control) + stmfd sp!, {r4, lr} + ldr r4, [sp, #8] @ FIXME: Is this right? + ldr r12, =__l4_capability_control + mov lr, pc @ We must return here to restore r4. + ldr pc, [r12] + ldmfd sp!, {r4, pc} +END_PROC(l4_capability_control) + /* * System call that unmaps an area of memory into the given address space. * @r0 = virtual, @r1 = pages, @r2 = tid of address space to unmap diff --git a/conts/posix/mm0/mm/init.c b/conts/posix/mm0/mm/init.c index 93fa1ea..714e374 100644 --- a/conts/posix/mm0/mm/init.c +++ b/conts/posix/mm0/mm/init.c @@ -179,6 +179,7 @@ void copy_boot_capabilities(int ncaps) capability_list.ncaps = ncaps; } +#if 0 /* * Our paged userspace shall have only the capability to do * ipc to us, and use no other system call. (Other than @@ -230,8 +231,170 @@ int setup_children_caps(void) } return 0; } +#endif -int read_pager_caps() +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; + list_foreach_struct(cap, &cap_list->caps, list) + cap_print(cap); +} +/* + * 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 *capability_list) +{ + struct capability ipc_cap, *cap; + struct task_ids ids; + int err; + + l4_getid(&ids); + + cap_list_print(capability_list); + + /* Find out our own ipc capability on our own container */ + list_foreach_struct(cap, &capability_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: + /* 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(); + } + + cap_list_print(capability_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 = __cid(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(capability_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(capability_list); + return 0; +} + +int pager_read_caps() { int ncaps; int err; @@ -239,7 +402,7 @@ int read_pager_caps() /* Read number of capabilities */ if ((err = l4_capability_control(CAP_CONTROL_NCAPS, - 0, &ncaps)) < 0) { + 0, 0, 0, &ncaps)) < 0) { printf("l4_capability_control() reading # of" " capabilities failed.\n Could not " "complete CAP_CONTROL_NCAPS request.\n"); @@ -252,7 +415,7 @@ int read_pager_caps() /* Read all capabilities */ if ((err = l4_capability_control(CAP_CONTROL_READ, - 0, caparray)) < 0) { + 0, 0, 0, caparray)) < 0) { printf("l4_capability_control() reading of " "capabilities failed.\n Could not " "complete CAP_CONTROL_READ_CAPS request.\n"); @@ -344,6 +507,12 @@ int read_pager_caps() 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 @@ -473,7 +642,7 @@ void init_physmem_secondary(struct membank *membank) membank[0].free += pg_npages * PAGE_SIZE; /* Update page bitmap for the pages used for the page array */ -+ set_page_map(pmap, pg_spfn, pg_epfn - pg_spfn, 1); + set_page_map(pmap, pg_spfn, pg_epfn - pg_spfn, 1); /* Initialise the page array */ for (int i = 0; i < npages; i++) { @@ -632,7 +801,7 @@ void start_init_process(void) void init(void) { - read_pager_capabilities(); + setup_caps(); pager_address_pool_init(); diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index 69395bd..88dcaff 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -98,12 +98,12 @@ #define CAP_UMUTEX_UNLOCK (1 << 1) /* Capability control capability */ -#define CAP_CAP_MODIFY (1 << 0) -#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) +#define CAP_CAP_GRANT (1 << 0) +#define CAP_CAP_READ (1 << 1) +#define CAP_CAP_SHARE (1 << 2) +#define CAP_CAP_REPLICATE (1 << 3) +#define CAP_CAP_SPLIT (1 << 4) +#define CAP_CAP_DEDUCE (1 << 5) +#define CAP_CAP_MODIFY (CAP_CAP_SPLIT | CAP_CAP_DEDUCE) #endif /* __CAP_TYPES_H__ */ diff --git a/scripts/kernel/generate_kernel_cinfo.py b/scripts/kernel/generate_kernel_cinfo.py index 976579d..9edbc1d 100755 --- a/scripts/kernel/generate_kernel_cinfo.py +++ b/scripts/kernel/generate_kernel_cinfo.py @@ -126,7 +126,9 @@ cap_all_others = \ \t\t\t}, \t\t\t[%d] = { \t\t\t\t.type = CAP_TYPE_CAP | CAP_RTYPE_CONTAINER, -\t\t\t\t.access = CAP_CAP_MODIFY | CAP_CAP_GRANT +\t\t\t\t.access = CAP_CAP_GRANT | CAP_CAP_READ +\t\t\t\t | CAP_CAP_SHARE | CAP_CAP_REPLICATE +\t\t\t\t | CAP_CAP_MODIFY \t\t\t\t| CAP_CAP_READ | CAP_CAP_SHARE, \t\t\t\t.start = 0, .end = 0, .size = 0, \t\t\t}, diff --git a/src/api/cap.c b/src/api/cap.c index cd16b05..4ed4a28 100644 --- a/src/api/cap.c +++ b/src/api/cap.c @@ -199,13 +199,13 @@ int cap_grant(unsigned int flags, l4id_t capid, l4id_t tid) * * orig = deduced; */ -int cap_deduce(l4id_t capid, struct capability *new) +int cap_deduce(struct capability *new) { struct capability *orig; struct address_space *sp; /* Find original capability */ - if (!(orig = cap_find_byid(capid))) + if (!(orig = cap_find_byid(new->capid))) return -EEXIST; /* Check that caller is owner */ @@ -218,7 +218,7 @@ int cap_deduce(l4id_t capid, struct capability *new) /* Check target resource deduction */ if (cap_rtype(new) != cap_rtype(orig)) { - /* An rtype deduction is always a space */ + /* An rtype deduction is always into a space */ if (cap_rtype(new) != CAP_RTYPE_SPACE) return -ENOCAP; @@ -250,9 +250,10 @@ int cap_deduce(l4id_t capid, struct capability *new) /* Deduce bits of orig */ orig->access &= new->access; - } + } else if (new->access) + return -EINVAL; - if (new->size) { + if (orig->size) { /* New can't have more, or make original redundant */ if (new->size >= orig->size) return -EINVAL; @@ -264,12 +265,27 @@ int cap_deduce(l4id_t capid, struct capability *new) if (new->size < orig->used) return -EPERM; orig->size = new->size; - } + } else if (new->size) + return -EINVAL; /* Range-like permissions can't be deduced */ - if (orig->start != new->start || - orig->end != new->end) - return -EPERM; + if (orig->start || orig->end) { + if (orig->start != new->start || + orig->end != new->end) + return -EPERM; + } else if (new->start || new->end) + return -EINVAL; + + /* Ensure orig and new are the same */ + BUG_ON(orig->capid != new->capid); + BUG_ON(orig->resid != new->resid); + BUG_ON(orig->owner != new->owner); + BUG_ON(orig->type != new->type); + BUG_ON(orig->access != new->access); + BUG_ON(orig->start != new->start); + BUG_ON(orig->end != new->end); + BUG_ON(orig->size != new->size); + BUG_ON(orig->used != new->used); return 0; } @@ -335,7 +351,8 @@ int cap_split(l4id_t capid, struct capability *diff) /* Assign given perms to new capability */ new->access = diff->access; - } + } else if (new->access) + return -EINVAL; /* Check size usage and split */ if (orig->size) { @@ -357,7 +374,9 @@ int cap_split(l4id_t capid, struct capability *diff) orig->size -= diff->size; new->size = diff->size; new->used = 0; - } + } else if (new->size) + return -EINVAL; + /* Check range usage but don't split if requested */ if (orig->start || orig->end) { @@ -367,7 +386,10 @@ int cap_split(l4id_t capid, struct capability *diff) free_capability(new); return -EPERM; } - } + } else if (new->start || new->end) + return -EINVAL; + + /* Copy other fields */ new->type = orig->type; @@ -377,6 +399,17 @@ int cap_split(l4id_t capid, struct capability *diff) /* Add the new capability to the most private list */ cap_list_insert(new, TASK_CAP_LIST(current)); + /* Copy the new one to diff for userspace */ + BUG_ON(new->resid != diff->resid); + BUG_ON(new->owner != diff->owner); + BUG_ON(new->type != diff->type); + BUG_ON(new->access != diff->access); + BUG_ON(new->start != diff->start); + BUG_ON(new->end != diff->end); + BUG_ON(new->size != diff->size); + BUG_ON(new->used != diff->used); + diff->capid = new->capid; + return 0; } @@ -464,7 +497,6 @@ int sys_capability_control(unsigned int req, unsigned int flags, /* Copy ncaps value. FIXME: This is only a partial list */ *((int *)userbuf) = TASK_CAP_LIST(current)->ncaps; break; - case CAP_CONTROL_READ: { /* Return all capabilities as an array of capabilities */ err = cap_read_all((struct capability *)userbuf); @@ -493,7 +525,7 @@ int sys_capability_control(unsigned int req, unsigned int flags, MAP_USR_RW_FLAGS, 1)) < 0) return err; - err = cap_deduce(capid, (struct capability *)userbuf); + err = cap_deduce((struct capability *)userbuf); break; default: