mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Fixed most of userspace (mm0) for capability manipulation
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user