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