Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset d24e987 in mainline


Ignore:
Timestamp:
2018-10-16T18:03:43Z (3 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
2d93763a, e344422
Parents:
c0cef6f9
git-author:
Jakub Jermar <jakub@…> (2018-10-16 17:55:57)
git-committer:
Jakub Jermar <jakub@…> (2018-10-16 18:03:43)
Message:

Make access via capabilities revokable

This commit makes it possible to revoke access to a kernel object from
all capabilities across all tasks. In order to support this, each kernel
object is equipped with a list of capabilities that point to it.

Location:
kernel/generic
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/cap/cap.h

    rc0cef6f9 rd24e987  
    6969
    7070/*
    71  * Everything in kobject_t except for the atomic reference count is imutable.
     71 * Everything in kobject_t except for the atomic reference count, the capability
     72 * list and its lock is imutable.
    7273 */
    7374typedef struct kobject {
    7475        kobject_type_t type;
    7576        atomic_t refcnt;
     77
     78        /** Mutex protecting caps_list */
     79        mutex_t caps_list_lock;
     80        /** List of published capabilities associated with the kobject */
     81        list_t caps_list;
    7682
    7783        kobject_ops_t *ops;
     
    9399        struct task *task;
    94100        cap_handle_t handle;
     101
     102        /** Link to the kobject's list of capabilities. */
     103        link_t kobj_link;
    95104
    96105        /* Link to the task's capabilities of the same kobject type. */
     
    122131extern void cap_publish(struct task *, cap_handle_t, kobject_t *);
    123132extern kobject_t *cap_unpublish(struct task *, cap_handle_t, kobject_type_t);
     133extern void cap_revoke(kobject_t *);
    124134extern void cap_free(struct task *, cap_handle_t);
    125135
  • kernel/generic/src/cap/cap.c

    rc0cef6f9 rd24e987  
    6363 * kobject_add_ref() or as a result of unpublishing a capability and
    6464 * disassociating it from its kobject_t using cap_unpublish().
     65 *
     66 * A holder of an explicit reference to a kernel object may revoke access to it
     67 * from all capabilities that point to it by calling cap_revoke().
    6568 *
    6669 * As kernel objects are reference-counted, they get automatically destroyed
     
    208211        cap->task = task;
    209212        cap->handle = handle;
     213        link_initialize(&cap->kobj_link);
    210214        link_initialize(&cap->type_link);
    211215}
     
    281285cap_publish(task_t *task, cap_handle_t handle, kobject_t *kobj)
    282286{
     287        mutex_lock(&kobj->caps_list_lock);
    283288        mutex_lock(&task->cap_info->lock);
    284289        cap_t *cap = cap_get(task, handle, CAP_STATE_ALLOCATED);
     
    287292        /* Hand over kobj's reference to cap */
    288293        cap->kobject = kobj;
     294        list_append(&cap->kobj_link, &kobj->caps_list);
    289295        list_append(&cap->type_link, &task->cap_info->type_list[kobj->type]);
    290296        mutex_unlock(&task->cap_info->lock);
     297        mutex_unlock(&kobj->caps_list_lock);
     298}
     299
     300static void cap_unpublish_unsafe(cap_t *cap)
     301{
     302        cap->kobject = NULL;
     303        list_remove(&cap->kobj_link);
     304        list_remove(&cap->type_link);
     305        cap->state = CAP_STATE_ALLOCATED;
    291306}
    292307
     
    302317 * @param type    Kernel object type of the object associated with the
    303318 *                capability.
     319 *
     320 * @return Pointer and explicit reference to the kobject that was associated
     321 *         with the capability.
    304322 */
    305323kobject_t *cap_unpublish(task_t *task, cap_handle_t handle, kobject_type_t type)
     
    307325        kobject_t *kobj = NULL;
    308326
     327restart:
    309328        mutex_lock(&task->cap_info->lock);
    310329        cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
     
    313332                        /* Hand over cap's reference to kobj */
    314333                        kobj = cap->kobject;
    315                         cap->kobject = NULL;
    316                         list_remove(&cap->type_link);
    317                         cap->state = CAP_STATE_ALLOCATED;
     334                        if (!mutex_trylock(&kobj->caps_list_lock)) {
     335                                mutex_unlock(&task->cap_info->lock);
     336                                kobj = NULL;
     337                                goto restart;
     338                        }
     339                        cap_unpublish_unsafe(cap);
     340                        mutex_unlock(&kobj->caps_list_lock);
    318341                }
    319342        }
     
    321344
    322345        return kobj;
     346}
     347
     348/** Revoke access to kobject from all existing capabilities
     349 *
     350 * All published capabilities associated with the kobject are unpublished (i.e.
     351 * their new state is set to CAP_STATE_ALLOCATED) and no longer point to the
     352 * kobject. Kobject's reference count is decreased accordingly.
     353 *
     354 * Note that the caller is supposed to hold an explicit reference to the kobject
     355 * so that the kobject is guaranteed to exist when this function returns.
     356 *
     357 * @param kobj  Pointer and explicit reference to the kobject capabilities of
     358 *              which are about to be unpublished.
     359 */
     360void cap_revoke(kobject_t *kobj)
     361{
     362        mutex_lock(&kobj->caps_list_lock);
     363        list_foreach_safe(kobj->caps_list, cur, hlp) {
     364                cap_t *cap = list_get_instance(cur, cap_t, kobj_link);
     365                mutex_lock(&cap->task->cap_info->lock);
     366                cap_unpublish_unsafe(cap);
     367                /* Drop the reference for the unpublished capability */
     368                kobject_put(kobj);
     369                mutex_unlock(&cap->task->cap_info->lock);
     370        }
     371        mutex_unlock(&kobj->caps_list_lock);
    323372}
    324373
     
    355404{
    356405        atomic_store(&kobj->refcnt, 1);
     406
     407        mutex_initialize(&kobj->caps_list_lock, MUTEX_PASSIVE);
     408        list_initialize(&kobj->caps_list);
     409
    357410        kobj->type = type;
    358411        kobj->raw = raw;
Note: See TracChangeset for help on using the changeset viewer.