linux/security/keys/persistent.c
<<
>>
Prefs
   1/* General persistent per-UID keyrings register
   2 *
   3 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#include <linux/user_namespace.h>
  13#include "internal.h"
  14
  15unsigned persistent_keyring_expiry = 3 * 24 * 3600; /* Expire after 3 days of non-use */
  16
  17/*
  18 * Create the persistent keyring register for the current user namespace.
  19 *
  20 * Called with the namespace's sem locked for writing.
  21 */
  22static int key_create_persistent_register(struct user_namespace *ns)
  23{
  24        struct key *reg = keyring_alloc(".persistent_register",
  25                                        KUIDT_INIT(0), KGIDT_INIT(0),
  26                                        current_cred(),
  27                                        ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
  28                                         KEY_USR_VIEW | KEY_USR_READ),
  29                                        KEY_ALLOC_NOT_IN_QUOTA, NULL);
  30        if (IS_ERR(reg))
  31                return PTR_ERR(reg);
  32
  33        ns->persistent_keyring_register = reg;
  34        return 0;
  35}
  36
  37/*
  38 * Create the persistent keyring for the specified user.
  39 *
  40 * Called with the namespace's sem locked for writing.
  41 */
  42static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
  43                                       struct keyring_index_key *index_key)
  44{
  45        struct key *persistent;
  46        key_ref_t reg_ref, persistent_ref;
  47
  48        if (!ns->persistent_keyring_register) {
  49                long err = key_create_persistent_register(ns);
  50                if (err < 0)
  51                        return ERR_PTR(err);
  52        } else {
  53                reg_ref = make_key_ref(ns->persistent_keyring_register, true);
  54                persistent_ref = find_key_to_update(reg_ref, index_key);
  55                if (persistent_ref)
  56                        return persistent_ref;
  57        }
  58
  59        persistent = keyring_alloc(index_key->description,
  60                                   uid, INVALID_GID, current_cred(),
  61                                   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
  62                                    KEY_USR_VIEW | KEY_USR_READ),
  63                                   KEY_ALLOC_NOT_IN_QUOTA,
  64                                   ns->persistent_keyring_register);
  65        if (IS_ERR(persistent))
  66                return ERR_CAST(persistent);
  67
  68        return make_key_ref(persistent, true);
  69}
  70
  71/*
  72 * Get the persistent keyring for a specific UID and link it to the nominated
  73 * keyring.
  74 */
  75static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
  76                               key_ref_t dest_ref)
  77{
  78        struct keyring_index_key index_key;
  79        struct key *persistent;
  80        key_ref_t reg_ref, persistent_ref;
  81        char buf[32];
  82        long ret;
  83
  84        /* Look in the register if it exists */
  85        index_key.type = &key_type_keyring;
  86        index_key.description = buf;
  87        index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid));
  88
  89        if (ns->persistent_keyring_register) {
  90                reg_ref = make_key_ref(ns->persistent_keyring_register, true);
  91                down_read(&ns->persistent_keyring_register_sem);
  92                persistent_ref = find_key_to_update(reg_ref, &index_key);
  93                up_read(&ns->persistent_keyring_register_sem);
  94
  95                if (persistent_ref)
  96                        goto found;
  97        }
  98
  99        /* It wasn't in the register, so we'll need to create it.  We might
 100         * also need to create the register.
 101         */
 102        down_write(&ns->persistent_keyring_register_sem);
 103        persistent_ref = key_create_persistent(ns, uid, &index_key);
 104        up_write(&ns->persistent_keyring_register_sem);
 105        if (!IS_ERR(persistent_ref))
 106                goto found;
 107
 108        return PTR_ERR(persistent_ref);
 109
 110found:
 111        ret = key_task_permission(persistent_ref, current_cred(), KEY_NEED_LINK);
 112        if (ret == 0) {
 113                persistent = key_ref_to_ptr(persistent_ref);
 114                ret = key_link(key_ref_to_ptr(dest_ref), persistent);
 115                if (ret == 0) {
 116                        key_set_timeout(persistent, persistent_keyring_expiry);
 117                        ret = persistent->serial;               
 118                }
 119        }
 120
 121        key_ref_put(persistent_ref);
 122        return ret;
 123}
 124
 125/*
 126 * Get the persistent keyring for a specific UID and link it to the nominated
 127 * keyring.
 128 */
 129long keyctl_get_persistent(uid_t _uid, key_serial_t destid)
 130{
 131        struct user_namespace *ns = current_user_ns();
 132        key_ref_t dest_ref;
 133        kuid_t uid;
 134        long ret;
 135
 136        /* -1 indicates the current user */
 137        if (_uid == (uid_t)-1) {
 138                uid = current_uid();
 139        } else {
 140                uid = make_kuid(ns, _uid);
 141                if (!uid_valid(uid))
 142                        return -EINVAL;
 143
 144                /* You can only see your own persistent cache if you're not
 145                 * sufficiently privileged.
 146                 */
 147                if (!uid_eq(uid, current_uid()) &&
 148                    !uid_eq(uid, current_euid()) &&
 149                    !ns_capable(ns, CAP_SETUID))
 150                        return -EPERM;
 151        }
 152
 153        /* There must be a destination keyring */
 154        dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
 155        if (IS_ERR(dest_ref))
 156                return PTR_ERR(dest_ref);
 157        if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) {
 158                ret = -ENOTDIR;
 159                goto out_put_dest;
 160        }
 161
 162        ret = key_get_persistent(ns, uid, dest_ref);
 163
 164out_put_dest:
 165        key_ref_put(dest_ref);
 166        return ret;
 167}
 168