Added routines for pager to search a suitable capability to grant to clients

Pager handles client capability requests by using one of its own
capabilities to create a new one that suits the client's needs.

The current issue is that the kernel can have multiple caps and it
may not know which one is suitable for using to create one for the client.

The kernel knows this very well, so the solution would be to attempt to
use capabilities that roughly match (i.e. by type) and leave it to
the kernel to decide whether it is any powerful to suit client's needs.
This commit is contained in:
Bahadir Balban
2009-11-08 17:54:57 +02:00
parent dc03c7b130
commit 1bb2c05c9b
3 changed files with 121 additions and 52 deletions

View File

@@ -23,6 +23,7 @@
#include <mmap.h> #include <mmap.h>
#include <test.h> #include <test.h>
#include <capability.h> #include <capability.h>
#include <globals.h>
/* Receives all registers and origies back */ /* Receives all registers and origies back */
int ipc_test_full_sync(l4id_t senderid) int ipc_test_full_sync(l4id_t senderid)

View File

@@ -14,6 +14,7 @@
#include <l4/generic/cap-types.h> /* TODO: Move this to API */ #include <l4/generic/cap-types.h> /* TODO: Move this to API */
#include <l4lib/arch/syslib.h> #include <l4lib/arch/syslib.h>
#include <malloc/malloc.h> #include <malloc/malloc.h>
#include <user.h>
/* Capability descriptor list */ /* Capability descriptor list */
struct cap_list capability_list; struct cap_list capability_list;
@@ -340,18 +341,16 @@ void setup_caps()
* replicate, reduce and grant as described with given parameters. * replicate, reduce and grant as described with given parameters.
* Assumes parameters have already been validated and security-checked. * Assumes parameters have already been validated and security-checked.
*/ */
int cap_find_reduce_grant(struct capability *cap) int cap_find_replicate_reduce_grant(struct capability *cap)
{ {
struct capability *possessed; struct capability *possessed;
struct capability new_cap; struct capability new_cap;
int err; int err;
/*
* Check for type
*/
list_foreach_struct(possessed, &capability_list.caps, list) { 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)) if (cap_type(possessed) == cap_type(cap))
goto found; goto found;
} }
@@ -432,51 +431,70 @@ found:
* capability if it is appropriate. This currently supports only * capability if it is appropriate. This currently supports only
* ipc. * ipc.
*/ */
int sys_request_cap(struct tcb *sender, struct capability *cap) int sys_request_cap(struct tcb *task, struct capability *__cap_userptr)
{ {
struct tcb *target; struct tcb *target;
int err; struct capability *cap;
int ret;
if (!(cap = pager_validate_map_user_range(task, __cap_userptr,
sizeof(*__cap_userptr),
VM_READ | VM_WRITE)))
return -EFAULT;
/* Only support IPC requests for now */ /* Only support IPC requests for now */
if (cap_type(cap) != CAP_TYPE_IPC) if (cap_type(cap) != CAP_TYPE_IPC) {
return -EPERM; ret = -EPERM;
goto out;
}
/* Validate rest of the fields */ /* Validate rest of the fields */
if (cap->start || cap->end || cap->used || cap->size) if (cap->start || cap->end || cap->used || cap->size) {
return -EINVAL; ret = -EINVAL;
goto out;
}
if (cap_generic_perms(cap) != CAP_IMMUTABLE) if (cap_generic_perms(cap) != CAP_IMMUTABLE) {
return -EPERM; ret = -EPERM;
goto out;
}
/* Find out who the task wants to ipc */ /* Find out who the task wants to ipc */
switch (cap_rtype(cap)) { switch (cap_rtype(cap)) {
/* Is it a thread? */ /* Is it a thread? */
case CAP_RTYPE_THREAD: case CAP_RTYPE_THREAD:
/* Find the thread */ /* Find the thread */
if (!(target = find_task(cap->resid))) if (!(target = find_task(cap->resid))) {
return -ESRCH; ret = -ESRCH;
goto out;
}
/* Requester must be the owner */ /* Requester must be the owner */
if (cap->owner != sender->tid) if (cap->owner != task->tid) {
return -EPERM; ret = -EPERM;
goto out;
}
/* /*
* It is a thread that we are managing, nothing * It is a thread that we are managing, nothing
* special requested here, just grant it * special requested here, just grant it
*/ */
if ((err = cap_find_reduce_grant(cap)) < 0) if ((ret = cap_find_replicate_reduce_grant(cap)) < 0)
return err; goto out;
break; break;
case CAP_RTYPE_SPACE: case CAP_RTYPE_SPACE:
/* Space requests not allowed */ /* Space requests not allowed */
return -EPERM; ret = -EPERM;
break; goto out;
case CAP_RTYPE_CONTAINER: case CAP_RTYPE_CONTAINER:
/* Container requests not allowed */ /* Container requests not allowed */
return -EPERM; ret = -EPERM;
break; goto out;
} }
return 0; out:
pager_unmap_user_range(__cap_userptr,
sizeof(*__cap_userptr));
return ret;
} }

View File

@@ -97,7 +97,7 @@ int cap_share(l4id_t capid, unsigned int flags)
} }
/* Grants all caps */ /* Grants all caps */
int cap_grant_all(l4id_t tid) int cap_grant_all(l4id_t tid, unsigned int flags)
{ {
struct ktcb *target; struct ktcb *target;
struct capability *cap_head, *cap; struct capability *cap_head, *cap;
@@ -113,6 +113,12 @@ int cap_grant_all(l4id_t tid)
/* Change ownership */ /* Change ownership */
cap->owner = target->tid; cap->owner = target->tid;
/* Make immutable if GRANT_IMMUTABLE given */
if (flags & CAP_GRANT_IMMUTABLE) {
cap->access &= ~CAP_GENERIC_MASK;
cap->access |= CAP_IMMUTABLE;
}
/* /*
* Sanity check: granted cap cannot have used * Sanity check: granted cap cannot have used
* quantity. Otherwise how else the original * quantity. Otherwise how else the original
@@ -134,7 +140,7 @@ out_err:
return err; return err;
} }
int cap_grant_single(l4id_t capid, l4id_t tid) int cap_grant_single(l4id_t capid, l4id_t tid, unsigned int flags)
{ {
struct capability *cap; struct capability *cap;
struct ktcb *target; struct ktcb *target;
@@ -158,23 +164,84 @@ int cap_grant_single(l4id_t capid, l4id_t tid)
/* Change ownership */ /* Change ownership */
cap->owner = target->tid; cap->owner = target->tid;
/* Make immutable if GRANT_IMMUTABLE given */
if (flags & CAP_GRANT_IMMUTABLE) {
cap->access &= ~CAP_GENERIC_MASK;
cap->access |= CAP_IMMUTABLE;
}
/* Place it where it is granted */ /* Place it where it is granted */
cap_list_insert(cap, TASK_CAP_LIST(target)); cap_list_insert(cap, TASK_CAP_LIST(target));
return 0; return 0;
} }
int cap_grant(unsigned int flags, l4id_t capid, l4id_t tid) int cap_grant(l4id_t capid, l4id_t tid, unsigned int flags)
{ {
if (flags & CAP_GRANT_SINGLE) if (flags & CAP_GRANT_SINGLE)
cap_grant_single(capid, tid); cap_grant_single(capid, tid, flags);
else if (flags & CAP_GRANT_ALL) else if (flags & CAP_GRANT_ALL)
cap_grant_all(tid); cap_grant_all(tid, flags);
else else
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
int cap_deduce_rtype(struct capability *orig, struct capability *new)
{
struct ktcb *target;
struct address_space *sp;
/* An rtype deduction can only be to a space or thread */
switch (cap_rtype(new)) {
case CAP_RTYPE_SPACE:
/* Check containment right */
if (cap_rtype(orig) != CAP_RTYPE_CONTAINER)
return -ENOCAP;
/*
* Find out if this space exists in this
* container.
*
* Note address space search is local only.
* Only thread searches are global.
*/
if (!(sp = address_space_find(new->resid)))
return -ENOCAP;
/* Success. Assign new type to original cap */
cap_set_rtype(orig, cap_rtype(new));
/* Assign the space id to orig cap */
orig->resid = sp->spid;
break;
case CAP_RTYPE_THREAD:
/* Find the thread */
if (!(target = tcb_find(new->resid)))
return -ENOCAP;
/* Check containment */
if (cap_rtype(orig) == CAP_RTYPE_SPACE) {
if (orig->resid != target->space->spid)
return -ENOCAP;
} else if (cap_rtype(orig) == CAP_RTYPE_CONTAINER) {
if(orig->resid != target->container->cid)
return -ENOCAP;
} else
return -ENOCAP;
/* Success. Assign new type to original cap */
cap_set_rtype(orig, cap_rtype(new));
/* Assign the space id to orig cap */
orig->resid = target->tid;
break;
default:
return -ENOCAP;
}
return 0;
}
/* /*
* Deduction can be by access permissions, start, end, size * Deduction can be by access permissions, start, end, size
* fields, or the target resource type. Inter-container * fields, or the target resource type. Inter-container
@@ -202,7 +269,7 @@ int cap_grant(unsigned int flags, l4id_t capid, l4id_t tid)
int cap_deduce(struct capability *new) int cap_deduce(struct capability *new)
{ {
struct capability *orig; struct capability *orig;
struct address_space *sp; int ret;
/* Find original capability */ /* Find original capability */
if (!(orig = cap_find_byid(new->capid))) if (!(orig = cap_find_byid(new->capid)))
@@ -217,27 +284,9 @@ int cap_deduce(struct capability *new)
return -ENOCAP; return -ENOCAP;
/* Check target resource deduction */ /* Check target resource deduction */
if (cap_rtype(new) != cap_rtype(orig)) { if (cap_rtype(new) != cap_rtype(orig))
/* An rtype deduction is always into a space */ if ((ret = cap_deduce_rtype(orig, new)) < 0)
if (cap_rtype(new) != CAP_RTYPE_SPACE) return ret;
return -ENOCAP;
/* Assign new type to original cap */
cap_set_rtype(orig, cap_rtype(new));
/*
* Find out if this space exists.
*
* Note address space search is
* local only. Only thread searches
* are global.
*/
if (!(sp = address_space_find(new->resid)))
return -ENOCAP;
/* Success. Assign the space id to orig cap */
orig->resid = sp->spid;
}
/* Check permissions for deduction */ /* Check permissions for deduction */
if (orig->access) { if (orig->access) {
@@ -253,6 +302,7 @@ int cap_deduce(struct capability *new)
} else if (new->access) } else if (new->access)
return -EINVAL; return -EINVAL;
/* Check size for deduction */
if (orig->size) { if (orig->size) {
/* New can't have more, or make original redundant */ /* New can't have more, or make original redundant */
if (new->size >= orig->size) if (new->size >= orig->size)