1 /* General persistent per-UID keyrings register
3 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/user_namespace.h>
15 unsigned persistent_keyring_expiry
= 3 * 24 * 3600; /* Expire after 3 days of non-use */
18 * Create the persistent keyring register for the current user namespace.
20 * Called with the namespace's sem locked for writing.
22 static int key_create_persistent_register(struct user_namespace
*ns
)
24 struct key
*reg
= keyring_alloc(".persistent_register",
25 KUIDT_INIT(0), KGIDT_INIT(0),
27 ((KEY_POS_ALL
& ~KEY_POS_SETATTR
) |
28 KEY_USR_VIEW
| KEY_USR_READ
),
29 KEY_ALLOC_NOT_IN_QUOTA
, NULL
, NULL
);
33 ns
->persistent_keyring_register
= reg
;
38 * Create the persistent keyring for the specified user.
40 * Called with the namespace's sem locked for writing.
42 static key_ref_t
key_create_persistent(struct user_namespace
*ns
, kuid_t uid
,
43 struct keyring_index_key
*index_key
)
45 struct key
*persistent
;
46 key_ref_t reg_ref
, persistent_ref
;
48 if (!ns
->persistent_keyring_register
) {
49 long err
= key_create_persistent_register(ns
);
53 reg_ref
= make_key_ref(ns
->persistent_keyring_register
, true);
54 persistent_ref
= find_key_to_update(reg_ref
, index_key
);
56 return persistent_ref
;
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
, NULL
,
64 ns
->persistent_keyring_register
);
65 if (IS_ERR(persistent
))
66 return ERR_CAST(persistent
);
68 return make_key_ref(persistent
, true);
72 * Get the persistent keyring for a specific UID and link it to the nominated
75 static long key_get_persistent(struct user_namespace
*ns
, kuid_t uid
,
78 struct keyring_index_key index_key
;
79 struct key
*persistent
;
80 key_ref_t reg_ref
, persistent_ref
;
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
));
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
);
99 /* It wasn't in the register, so we'll need to create it. We might
100 * also need to create the register.
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
))
108 return PTR_ERR(persistent_ref
);
111 ret
= key_task_permission(persistent_ref
, current_cred(), KEY_NEED_LINK
);
113 persistent
= key_ref_to_ptr(persistent_ref
);
114 ret
= key_link(key_ref_to_ptr(dest_ref
), persistent
);
116 key_set_timeout(persistent
, persistent_keyring_expiry
);
117 ret
= persistent
->serial
;
121 key_ref_put(persistent_ref
);
126 * Get the persistent keyring for a specific UID and link it to the nominated
129 long keyctl_get_persistent(uid_t _uid
, key_serial_t destid
)
131 struct user_namespace
*ns
= current_user_ns();
136 /* -1 indicates the current user */
137 if (_uid
== (uid_t
)-1) {
140 uid
= make_kuid(ns
, _uid
);
144 /* You can only see your own persistent cache if you're not
145 * sufficiently privileged.
147 if (!uid_eq(uid
, current_uid()) &&
148 !uid_eq(uid
, current_euid()) &&
149 !ns_capable(ns
, CAP_SETUID
))
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
) {
162 ret
= key_get_persistent(ns
, uid
, dest_ref
);
165 key_ref_put(dest_ref
);