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