aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-10-30 07:15:24 -0400
committerDavid Howells <dhowells@redhat.com>2013-10-30 07:15:24 -0400
commit034faeb9ef390d58239e1dce748143f6b35a0d9b (patch)
treef2239231b251a064e0f8d4b5c34cf4ef04586992 /security/keys
parent74792b0001ee85b845dc82c1a716c6052c2db9de (diff)
KEYS: Fix keyring quota misaccounting on key replacement and unlink
If a key is displaced from a keyring by a matching one, then four more bytes of quota are allocated to the keyring - despite the fact that the keyring does not change in size. Further, when a key is unlinked from a keyring, the four bytes of quota allocated the link isn't recovered and returned to the user's pool. The first can be tested by repeating: keyctl add big_key a fred @s cat /proc/key-users (Don't put it in a shell loop otherwise the garbage collector won't have time to clear the displaced keys, thus affecting the result). This was causing the kerberos keyring to run out of room fairly quickly. The second can be tested by: cat /proc/key-users a=`keyctl add user a a @s` cat /proc/key-users keyctl unlink $a sleep 1 # Give RCU a chance to delete the key cat /proc/key-users assuming no system activity that otherwise adds/removes keys, the amount of key data allocated should go up (say 40/20000 -> 47/20000) and then return to the original value at the end. Reported-by: Stephen Gallagher <sgallagh@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/keyring.c27
1 files changed, 15 insertions, 12 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 8c05ebd7203d..d80311e571c3 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1063,12 +1063,6 @@ int __key_link_begin(struct key *keyring,
1063 if (index_key->type == &key_type_keyring) 1063 if (index_key->type == &key_type_keyring)
1064 down_write(&keyring_serialise_link_sem); 1064 down_write(&keyring_serialise_link_sem);
1065 1065
1066 /* check that we aren't going to overrun the user's quota */
1067 ret = key_payload_reserve(keyring,
1068 keyring->datalen + KEYQUOTA_LINK_BYTES);
1069 if (ret < 0)
1070 goto error_sem;
1071
1072 /* Create an edit script that will insert/replace the key in the 1066 /* Create an edit script that will insert/replace the key in the
1073 * keyring tree. 1067 * keyring tree.
1074 */ 1068 */
@@ -1078,17 +1072,25 @@ int __key_link_begin(struct key *keyring,
1078 NULL); 1072 NULL);
1079 if (IS_ERR(edit)) { 1073 if (IS_ERR(edit)) {
1080 ret = PTR_ERR(edit); 1074 ret = PTR_ERR(edit);
1081 goto error_quota; 1075 goto error_sem;
1076 }
1077
1078 /* If we're not replacing a link in-place then we're going to need some
1079 * extra quota.
1080 */
1081 if (!edit->dead_leaf) {
1082 ret = key_payload_reserve(keyring,
1083 keyring->datalen + KEYQUOTA_LINK_BYTES);
1084 if (ret < 0)
1085 goto error_cancel;
1082 } 1086 }
1083 1087
1084 *_edit = edit; 1088 *_edit = edit;
1085 kleave(" = 0"); 1089 kleave(" = 0");
1086 return 0; 1090 return 0;
1087 1091
1088error_quota: 1092error_cancel:
1089 /* undo the quota changes */ 1093 assoc_array_cancel_edit(edit);
1090 key_payload_reserve(keyring,
1091 keyring->datalen - KEYQUOTA_LINK_BYTES);
1092error_sem: 1094error_sem:
1093 if (index_key->type == &key_type_keyring) 1095 if (index_key->type == &key_type_keyring)
1094 up_write(&keyring_serialise_link_sem); 1096 up_write(&keyring_serialise_link_sem);
@@ -1146,7 +1148,7 @@ void __key_link_end(struct key *keyring,
1146 if (index_key->type == &key_type_keyring) 1148 if (index_key->type == &key_type_keyring)
1147 up_write(&keyring_serialise_link_sem); 1149 up_write(&keyring_serialise_link_sem);
1148 1150
1149 if (edit) { 1151 if (edit && !edit->dead_leaf) {
1150 key_payload_reserve(keyring, 1152 key_payload_reserve(keyring,
1151 keyring->datalen - KEYQUOTA_LINK_BYTES); 1153 keyring->datalen - KEYQUOTA_LINK_BYTES);
1152 assoc_array_cancel_edit(edit); 1154 assoc_array_cancel_edit(edit);
@@ -1243,6 +1245,7 @@ int key_unlink(struct key *keyring, struct key *key)
1243 goto error; 1245 goto error;
1244 1246
1245 assoc_array_apply_edit(edit); 1247 assoc_array_apply_edit(edit);
1248 key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES);
1246 ret = 0; 1249 ret = 0;
1247 1250
1248error: 1251error: