diff --git a/conts/posix/mm0/main.c b/conts/posix/mm0/main.c index 4bd042e..61bd30e 100644 --- a/conts/posix/mm0/main.c +++ b/conts/posix/mm0/main.c @@ -23,6 +23,7 @@ #include #include #include +#include /* Receives all registers and origies back */ int ipc_test_full_sync(l4id_t senderid) diff --git a/conts/posix/mm0/mm/capability.c b/conts/posix/mm0/mm/capability.c index ebd6c77..1e71661 100644 --- a/conts/posix/mm0/mm/capability.c +++ b/conts/posix/mm0/mm/capability.c @@ -14,6 +14,7 @@ #include /* TODO: Move this to API */ #include #include +#include /* Capability descriptor list */ struct cap_list capability_list; @@ -340,18 +341,16 @@ void setup_caps() * 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) +int cap_find_replicate_reduce_grant(struct capability *cap) { struct capability *possessed; struct capability new_cap; int err; + /* + * Check for type + */ 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; } @@ -432,51 +431,70 @@ found: * capability if it is appropriate. This currently supports only * 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; - 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 */ - if (cap_type(cap) != CAP_TYPE_IPC) - return -EPERM; + if (cap_type(cap) != CAP_TYPE_IPC) { + ret = -EPERM; + goto out; + } /* Validate rest of the fields */ - if (cap->start || cap->end || cap->used || cap->size) - return -EINVAL; + if (cap->start || cap->end || cap->used || cap->size) { + ret = -EINVAL; + goto out; + } - if (cap_generic_perms(cap) != CAP_IMMUTABLE) - return -EPERM; + if (cap_generic_perms(cap) != CAP_IMMUTABLE) { + ret = -EPERM; + goto out; + } /* 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; + if (!(target = find_task(cap->resid))) { + ret = -ESRCH; + goto out; + } /* Requester must be the owner */ - if (cap->owner != sender->tid) - return -EPERM; + if (cap->owner != task->tid) { + ret = -EPERM; + goto out; + } /* * 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; + if ((ret = cap_find_replicate_reduce_grant(cap)) < 0) + goto out; break; case CAP_RTYPE_SPACE: /* Space requests not allowed */ - return -EPERM; - break; + ret = -EPERM; + goto out; case CAP_RTYPE_CONTAINER: /* Container requests not allowed */ - return -EPERM; - break; + ret = -EPERM; + goto out; } - return 0; +out: + pager_unmap_user_range(__cap_userptr, + sizeof(*__cap_userptr)); + return ret; } diff --git a/src/api/cap.c b/src/api/cap.c index 4ade8ae..dce2c3a 100644 --- a/src/api/cap.c +++ b/src/api/cap.c @@ -97,7 +97,7 @@ int cap_share(l4id_t capid, unsigned int flags) } /* Grants all caps */ -int cap_grant_all(l4id_t tid) +int cap_grant_all(l4id_t tid, unsigned int flags) { struct ktcb *target; struct capability *cap_head, *cap; @@ -113,6 +113,12 @@ int cap_grant_all(l4id_t tid) /* Change ownership */ 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 * quantity. Otherwise how else the original @@ -134,7 +140,7 @@ out_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 ktcb *target; @@ -158,23 +164,84 @@ int cap_grant_single(l4id_t capid, l4id_t tid) /* Change ownership */ 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 */ cap_list_insert(cap, TASK_CAP_LIST(target)); 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) - cap_grant_single(capid, tid); + cap_grant_single(capid, tid, flags); else if (flags & CAP_GRANT_ALL) - cap_grant_all(tid); + cap_grant_all(tid, flags); else return -EINVAL; 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 * 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) { struct capability *orig; - struct address_space *sp; + int ret; /* Find original capability */ if (!(orig = cap_find_byid(new->capid))) @@ -217,27 +284,9 @@ int cap_deduce(struct capability *new) return -ENOCAP; /* Check target resource deduction */ - if (cap_rtype(new) != cap_rtype(orig)) { - /* An rtype deduction is always into a space */ - if (cap_rtype(new) != CAP_RTYPE_SPACE) - 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; - } + if (cap_rtype(new) != cap_rtype(orig)) + if ((ret = cap_deduce_rtype(orig, new)) < 0) + return ret; /* Check permissions for deduction */ if (orig->access) { @@ -253,6 +302,7 @@ int cap_deduce(struct capability *new) } else if (new->access) return -EINVAL; + /* Check size for deduction */ if (orig->size) { /* New can't have more, or make original redundant */ if (new->size >= orig->size)