aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-05-11 05:56:56 -0400
committerDavid Howells <dhowells@redhat.com>2012-05-11 05:56:56 -0400
commit31d5a79d7f3d436da176a78ebc12d53c06da402e (patch)
treed39a75d7d0d0e85102ff8ce5e55e5d6ab7db7262
parent233e4735f2a45d9e641c2488b8d7afeb1f377dac (diff)
KEYS: Do LRU discard in full keyrings
Do an LRU discard in keyrings that are full rather than returning ENFILE. To perform this, a time_t is added to the key struct and updated by the creation of a link to a key and by a key being found as the result of a search. At the completion of a successful search, the keyrings in the path between the root of the search and the first found link to it also have their last-used times updated. Note that discarding a link to a key from a keyring does not necessarily destroy the key as there may be references held by other places. An alternate discard method that might suffice is to perform FIFO discard from the keyring, using the spare 2-byte hole in the keylist header as the index of the next link to be discarded. This is useful when using a keyring as a cache for DNS results or foreign filesystem IDs. This can be tested by the following. As root do: echo 1000 >/proc/sys/kernel/keys/root_maxkeys kr=`keyctl newring foo @s` for ((i=0; i<2000; i++)); do keyctl add user a$i a $kr; done Without this patch ENFILE should be reported when the keyring fills up. With this patch, the keyring discards keys in an LRU fashion. Note that the stored LRU time has a granularity of 1s. After doing this, /proc/key-users can be observed and should show that most of the 2000 keys have been discarded: [root@andromeda ~]# cat /proc/key-users 0: 517 516/516 513/1000 5249/20000 The "513/1000" here is the number of quota-accounted keys present for this user out of the maximum permitted. In /proc/keys, the keyring shows the number of keys it has and the number of slots it has allocated: [root@andromeda ~]# grep foo /proc/keys 200c64c4 I--Q-- 1 perm 3b3f0000 0 0 keyring foo: 509/509 The maximum is (PAGE_SIZE - header) / key pointer size. That's typically 509 on a 64-bit system and 1020 on a 32-bit system. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--include/linux/key.h1
-rw-r--r--security/keys/keyring.c47
-rw-r--r--security/keys/process_keys.c2
3 files changed, 43 insertions, 7 deletions
diff --git a/include/linux/key.h b/include/linux/key.h
index c505f83c9691..13c0dcd8ee48 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -136,6 +136,7 @@ struct key {
136 time_t expiry; /* time at which key expires (or 0) */ 136 time_t expiry; /* time at which key expires (or 0) */
137 time_t revoked_at; /* time at which key was revoked */ 137 time_t revoked_at; /* time at which key was revoked */
138 }; 138 };
139 time_t last_used_at; /* last time used for LRU keyring discard */
139 uid_t uid; 140 uid_t uid;
140 gid_t gid; 141 gid_t gid;
141 key_perm_t perm; /* access permissions */ 142 key_perm_t perm; /* access permissions */
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 459b3cc347f2..89d02cfb00c2 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -30,6 +30,10 @@
30 (klist)->keys[index], \ 30 (klist)->keys[index], \
31 rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) 31 rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
32 32
33#define MAX_KEYRING_LINKS \
34 min_t(size_t, USHRT_MAX - 1, \
35 ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *)))
36
33#define KEY_LINK_FIXQUOTA 1UL 37#define KEY_LINK_FIXQUOTA 1UL
34 38
35/* 39/*
@@ -319,6 +323,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
319 bool no_state_check) 323 bool no_state_check)
320{ 324{
321 struct { 325 struct {
326 /* Need a separate keylist pointer for RCU purposes */
327 struct key *keyring;
322 struct keyring_list *keylist; 328 struct keyring_list *keylist;
323 int kix; 329 int kix;
324 } stack[KEYRING_SEARCH_MAX_DEPTH]; 330 } stack[KEYRING_SEARCH_MAX_DEPTH];
@@ -451,6 +457,7 @@ ascend:
451 continue; 457 continue;
452 458
453 /* stack the current position */ 459 /* stack the current position */
460 stack[sp].keyring = keyring;
454 stack[sp].keylist = keylist; 461 stack[sp].keylist = keylist;
455 stack[sp].kix = kix; 462 stack[sp].kix = kix;
456 sp++; 463 sp++;
@@ -466,6 +473,7 @@ not_this_keyring:
466 if (sp > 0) { 473 if (sp > 0) {
467 /* resume the processing of a keyring higher up in the tree */ 474 /* resume the processing of a keyring higher up in the tree */
468 sp--; 475 sp--;
476 keyring = stack[sp].keyring;
469 keylist = stack[sp].keylist; 477 keylist = stack[sp].keylist;
470 kix = stack[sp].kix + 1; 478 kix = stack[sp].kix + 1;
471 goto ascend; 479 goto ascend;
@@ -477,6 +485,10 @@ not_this_keyring:
477 /* we found a viable match */ 485 /* we found a viable match */
478found: 486found:
479 atomic_inc(&key->usage); 487 atomic_inc(&key->usage);
488 key->last_used_at = now.tv_sec;
489 keyring->last_used_at = now.tv_sec;
490 while (sp > 0)
491 stack[--sp].keyring->last_used_at = now.tv_sec;
480 key_check(key); 492 key_check(key);
481 key_ref = make_key_ref(key, possessed); 493 key_ref = make_key_ref(key, possessed);
482error_2: 494error_2:
@@ -558,6 +570,8 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
558 570
559found: 571found:
560 atomic_inc(&key->usage); 572 atomic_inc(&key->usage);
573 keyring->last_used_at = key->last_used_at =
574 current_kernel_time().tv_sec;
561 rcu_read_unlock(); 575 rcu_read_unlock();
562 return make_key_ref(key, possessed); 576 return make_key_ref(key, possessed);
563} 577}
@@ -611,6 +625,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
611 * (ie. it has a zero usage count) */ 625 * (ie. it has a zero usage count) */
612 if (!atomic_inc_not_zero(&keyring->usage)) 626 if (!atomic_inc_not_zero(&keyring->usage))
613 continue; 627 continue;
628 keyring->last_used_at = current_kernel_time().tv_sec;
614 goto out; 629 goto out;
615 } 630 }
616 } 631 }
@@ -734,8 +749,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
734 struct keyring_list *klist, *nklist; 749 struct keyring_list *klist, *nklist;
735 unsigned long prealloc; 750 unsigned long prealloc;
736 unsigned max; 751 unsigned max;
752 time_t lowest_lru;
737 size_t size; 753 size_t size;
738 int loop, ret; 754 int loop, lru, ret;
739 755
740 kenter("%d,%s,%s,", key_serial(keyring), type->name, description); 756 kenter("%d,%s,%s,", key_serial(keyring), type->name, description);
741 757
@@ -756,7 +772,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
756 klist = rcu_dereference_locked_keyring(keyring); 772 klist = rcu_dereference_locked_keyring(keyring);
757 773
758 /* see if there's a matching key we can displace */ 774 /* see if there's a matching key we can displace */
775 lru = -1;
759 if (klist && klist->nkeys > 0) { 776 if (klist && klist->nkeys > 0) {
777 lowest_lru = TIME_T_MAX;
760 for (loop = klist->nkeys - 1; loop >= 0; loop--) { 778 for (loop = klist->nkeys - 1; loop >= 0; loop--) {
761 struct key *key = rcu_deref_link_locked(klist, loop, 779 struct key *key = rcu_deref_link_locked(klist, loop,
762 keyring); 780 keyring);
@@ -770,9 +788,23 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
770 prealloc = 0; 788 prealloc = 0;
771 goto done; 789 goto done;
772 } 790 }
791 if (key->last_used_at < lowest_lru) {
792 lowest_lru = key->last_used_at;
793 lru = loop;
794 }
773 } 795 }
774 } 796 }
775 797
798 /* If the keyring is full then do an LRU discard */
799 if (klist &&
800 klist->nkeys == klist->maxkeys &&
801 klist->maxkeys >= MAX_KEYRING_LINKS) {
802 kdebug("LRU discard %d\n", lru);
803 klist->delkey = lru;
804 prealloc = 0;
805 goto done;
806 }
807
776 /* check that we aren't going to overrun the user's quota */ 808 /* check that we aren't going to overrun the user's quota */
777 ret = key_payload_reserve(keyring, 809 ret = key_payload_reserve(keyring,
778 keyring->datalen + KEYQUOTA_LINK_BYTES); 810 keyring->datalen + KEYQUOTA_LINK_BYTES);
@@ -786,15 +818,14 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
786 } else { 818 } else {
787 /* grow the key list */ 819 /* grow the key list */
788 max = 4; 820 max = 4;
789 if (klist) 821 if (klist) {
790 max += klist->maxkeys; 822 max += klist->maxkeys;
823 if (max > MAX_KEYRING_LINKS)
824 max = MAX_KEYRING_LINKS;
825 BUG_ON(max <= klist->maxkeys);
826 }
791 827
792 ret = -ENFILE;
793 if (max > USHRT_MAX - 1)
794 goto error_quota;
795 size = sizeof(*klist) + sizeof(struct key *) * max; 828 size = sizeof(*klist) + sizeof(struct key *) * max;
796 if (size > PAGE_SIZE)
797 goto error_quota;
798 829
799 ret = -ENOMEM; 830 ret = -ENOMEM;
800 nklist = kmalloc(size, GFP_KERNEL); 831 nklist = kmalloc(size, GFP_KERNEL);
@@ -873,6 +904,8 @@ void __key_link(struct key *keyring, struct key *key,
873 klist = rcu_dereference_locked_keyring(keyring); 904 klist = rcu_dereference_locked_keyring(keyring);
874 905
875 atomic_inc(&key->usage); 906 atomic_inc(&key->usage);
907 keyring->last_used_at = key->last_used_at =
908 current_kernel_time().tv_sec;
876 909
877 /* there's a matching key we can displace or an empty slot in a newly 910 /* there's a matching key we can displace or an empty slot in a newly
878 * allocated list we can fill */ 911 * allocated list we can fill */
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index be7ecb2018dd..e137fcd7042c 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -732,6 +732,8 @@ try_again:
732 if (ret < 0) 732 if (ret < 0)
733 goto invalid_key; 733 goto invalid_key;
734 734
735 key->last_used_at = current_kernel_time().tv_sec;
736
735error: 737error:
736 put_cred(cred); 738 put_cred(cred);
737 return key_ref; 739 return key_ref;