linux/security/keys/persistent.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* General persistent per-UID keyrings register
   3 *
   4 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#include <linux/user_namespace.h>
   9#include <linux/cred.h>
  10
  11#include "internal.h"
  12
  13unsigned persistent_keyring_expiry = 3 * 24 * 3600; /* Expire after 3 days of non-use */
  14
  15/*
  16 * Create the persistent keyring register for the current user namespace.
  17 *
  18 * Called with the namespace's sem locked for writing.
  19 */
  20static int key_create_persistent_register(struct user_namespace *ns)
  21{
  22        struct key *reg = keyring_alloc(".persistent_register",
  23                                        KUIDT_INIT(0), KGIDT_INIT(0),
  24                                        current_cred(),
  25                                        ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
  26                                         KEY_USR_VIEW | KEY_USR_READ),
  27                                        KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
  28        if (IS_ERR(reg))
  29                return PTR_ERR(reg);
  30
  31        ns->persistent_keyring_register = reg;
  32        return 0;
  33}
  34
  35/*
  36 * Create the persistent keyring for the specified user.
  37 *
  38 * Called with the namespace's sem locked for writing.
  39 */
  40static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
  41                                       struct keyring_index_key *index_key)
  42{
  43        struct key *persistent;
  44        key_ref_t reg_ref, persistent_ref;
  45
  46        if (!ns->persistent_keyring_register) {
  47                long err = key_create_persistent_register(ns);
  48                if (err < 0)
  49                        return ERR_PTR(err);
  50        } else {
  51                reg_ref = make_key_ref(ns->persistent_keyring_register, true);
  52                persistent_ref = find_key_to_update(reg_ref, index_key);
  53                if (persistent_ref)
  54                        return persistent_ref;
  55        }
  56
  57        persistent = keyring_alloc(index_key->description,
  58                                   uid, INVALID_GID, current_cred(),
  59                                   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
  60                                    KEY_USR_VIEW | KEY_USR_READ),
  61                                   KEY_ALLOC_NOT_IN_QUOTA, NULL,
  62                                   ns->persistent_keyring_register);
  63        if (IS_ERR(persistent))
  64                return ERR_CAST(persistent);
  65
  66        return make_key_ref(persistent, true);
  67}
  68
  69/*
  70 * Get the persistent keyring for a specific UID and link it to the nominated
  71 * keyring.
  72 */
  73static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
  74                               key_ref_t dest_ref)
  75{
  76        struct keyring_index_key index_key;
  77        struct key *persistent;
  78        key_ref_t reg_ref, persistent_ref;
  79        char buf[32];
  80        long ret;
  81
  82        /* Look in the register if it exists */
  83        memset(&index_key, 0, sizeof(index_key));
  84        index_key.type = &key_type_keyring;
  85        index_key.description = buf;
  86        index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid));
  87        key_set_index_key(&index_key);
  88
  89        if (ns->persistent_keyring_register) {
  90                reg_ref = make_key_ref(ns->persistent_keyring_register, true);
  91                down_read(&ns->keyring_sem);
  92                persistent_ref = find_key_to_update(reg_ref, &index_key);
  93                up_read(&ns->keyring_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->keyring_sem);
 103        persistent_ref = key_create_persistent(ns, uid, &index_key);
 104        up_write(&ns->keyring_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