aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/gc.c78
-rw-r--r--security/keys/key.c4
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--security/keys/keyring.c24
4 files changed, 73 insertions, 35 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 1e616aef55fd..485fc6233c38 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -26,8 +26,10 @@ static void key_garbage_collector(struct work_struct *);
26static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); 26static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
27static DECLARE_WORK(key_gc_work, key_garbage_collector); 27static DECLARE_WORK(key_gc_work, key_garbage_collector);
28static key_serial_t key_gc_cursor; /* the last key the gc considered */ 28static key_serial_t key_gc_cursor; /* the last key the gc considered */
29static bool key_gc_again;
29static unsigned long key_gc_executing; 30static unsigned long key_gc_executing;
30static time_t key_gc_next_run = LONG_MAX; 31static time_t key_gc_next_run = LONG_MAX;
32static time_t key_gc_new_timer;
31 33
32/* 34/*
33 * Schedule a garbage collection run 35 * Schedule a garbage collection run
@@ -40,9 +42,7 @@ void key_schedule_gc(time_t gc_at)
40 42
41 kenter("%ld", gc_at - now); 43 kenter("%ld", gc_at - now);
42 44
43 gc_at += key_gc_delay; 45 if (gc_at <= now) {
44
45 if (now >= gc_at) {
46 schedule_work(&key_gc_work); 46 schedule_work(&key_gc_work);
47 } else if (gc_at < key_gc_next_run) { 47 } else if (gc_at < key_gc_next_run) {
48 expires = jiffies + (gc_at - now) * HZ; 48 expires = jiffies + (gc_at - now) * HZ;
@@ -112,16 +112,18 @@ static void key_garbage_collector(struct work_struct *work)
112 struct rb_node *rb; 112 struct rb_node *rb;
113 key_serial_t cursor; 113 key_serial_t cursor;
114 struct key *key, *xkey; 114 struct key *key, *xkey;
115 time_t new_timer = LONG_MAX, limit; 115 time_t new_timer = LONG_MAX, limit, now;
116 116
117 kenter(""); 117 now = current_kernel_time().tv_sec;
118 kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now);
118 119
119 if (test_and_set_bit(0, &key_gc_executing)) { 120 if (test_and_set_bit(0, &key_gc_executing)) {
120 key_schedule_gc(current_kernel_time().tv_sec); 121 key_schedule_gc(current_kernel_time().tv_sec + 1);
122 kleave(" [busy; deferring]");
121 return; 123 return;
122 } 124 }
123 125
124 limit = current_kernel_time().tv_sec; 126 limit = now;
125 if (limit > key_gc_delay) 127 if (limit > key_gc_delay)
126 limit -= key_gc_delay; 128 limit -= key_gc_delay;
127 else 129 else
@@ -129,12 +131,19 @@ static void key_garbage_collector(struct work_struct *work)
129 131
130 spin_lock(&key_serial_lock); 132 spin_lock(&key_serial_lock);
131 133
132 if (RB_EMPTY_ROOT(&key_serial_tree)) 134 if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) {
133 goto reached_the_end; 135 spin_unlock(&key_serial_lock);
136 clear_bit(0, &key_gc_executing);
137 return;
138 }
134 139
135 cursor = key_gc_cursor; 140 cursor = key_gc_cursor;
136 if (cursor < 0) 141 if (cursor < 0)
137 cursor = 0; 142 cursor = 0;
143 if (cursor > 0)
144 new_timer = key_gc_new_timer;
145 else
146 key_gc_again = false;
138 147
139 /* find the first key above the cursor */ 148 /* find the first key above the cursor */
140 key = NULL; 149 key = NULL;
@@ -160,35 +169,50 @@ static void key_garbage_collector(struct work_struct *work)
160 169
161 /* trawl through the keys looking for keyrings */ 170 /* trawl through the keys looking for keyrings */
162 for (;;) { 171 for (;;) {
163 if (key->expiry > 0 && key->expiry < new_timer) 172 if (key->expiry > now && key->expiry < new_timer) {
173 kdebug("will expire %x in %ld",
174 key_serial(key), key->expiry - now);
164 new_timer = key->expiry; 175 new_timer = key->expiry;
176 }
165 177
166 if (key->type == &key_type_keyring && 178 if (key->type == &key_type_keyring &&
167 key_gc_keyring(key, limit)) { 179 key_gc_keyring(key, limit))
168 /* the gc ate our lock */ 180 /* the gc had to release our lock so that the keyring
169 schedule_work(&key_gc_work); 181 * could be modified, so we have to get it again */
170 goto no_unlock; 182 goto gc_released_our_lock;
171 }
172 183
173 rb = rb_next(&key->serial_node); 184 rb = rb_next(&key->serial_node);
174 if (!rb) { 185 if (!rb)
175 key_gc_cursor = 0; 186 goto reached_the_end;
176 break;
177 }
178 key = rb_entry(rb, struct key, serial_node); 187 key = rb_entry(rb, struct key, serial_node);
179 } 188 }
180 189
181out: 190gc_released_our_lock:
182 spin_unlock(&key_serial_lock); 191 kdebug("gc_released_our_lock");
183no_unlock: 192 key_gc_new_timer = new_timer;
193 key_gc_again = true;
184 clear_bit(0, &key_gc_executing); 194 clear_bit(0, &key_gc_executing);
185 if (new_timer < LONG_MAX) 195 schedule_work(&key_gc_work);
186 key_schedule_gc(new_timer); 196 kleave(" [continue]");
187
188 kleave("");
189 return; 197 return;
190 198
199 /* when we reach the end of the run, we set the timer for the next one */
191reached_the_end: 200reached_the_end:
201 kdebug("reached_the_end");
202 spin_unlock(&key_serial_lock);
203 key_gc_new_timer = new_timer;
192 key_gc_cursor = 0; 204 key_gc_cursor = 0;
193 goto out; 205 clear_bit(0, &key_gc_executing);
206
207 if (key_gc_again) {
208 /* there may have been a key that expired whilst we were
209 * scanning, so if we discarded any links we should do another
210 * scan */
211 new_timer = now + 1;
212 key_schedule_gc(new_timer);
213 } else if (new_timer < LONG_MAX) {
214 new_timer += key_gc_delay;
215 key_schedule_gc(new_timer);
216 }
217 kleave(" [end]");
194} 218}
diff --git a/security/keys/key.c b/security/keys/key.c
index 08531ad0f252..e50d264c9ad1 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -500,7 +500,7 @@ int key_negate_and_link(struct key *key,
500 set_bit(KEY_FLAG_INSTANTIATED, &key->flags); 500 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
501 now = current_kernel_time(); 501 now = current_kernel_time();
502 key->expiry = now.tv_sec + timeout; 502 key->expiry = now.tv_sec + timeout;
503 key_schedule_gc(key->expiry); 503 key_schedule_gc(key->expiry + key_gc_delay);
504 504
505 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) 505 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
506 awaken = 1; 506 awaken = 1;
@@ -909,7 +909,7 @@ void key_revoke(struct key *key)
909 time = now.tv_sec; 909 time = now.tv_sec;
910 if (key->revoked_at == 0 || key->revoked_at > time) { 910 if (key->revoked_at == 0 || key->revoked_at > time) {
911 key->revoked_at = time; 911 key->revoked_at = time;
912 key_schedule_gc(key->revoked_at); 912 key_schedule_gc(key->revoked_at + key_gc_delay);
913 } 913 }
914 914
915 up_write(&key->sem); 915 up_write(&key->sem);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 60983f38852e..2fb28efc5326 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1115,7 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
1115 } 1115 }
1116 1116
1117 key->expiry = expiry; 1117 key->expiry = expiry;
1118 key_schedule_gc(key->expiry); 1118 key_schedule_gc(key->expiry + key_gc_delay);
1119 1119
1120 up_write(&key->sem); 1120 up_write(&key->sem);
1121 key_put(key); 1121 key_put(key);
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index ac977f661a79..8ec02746ca99 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1019,18 +1019,18 @@ void keyring_gc(struct key *keyring, time_t limit)
1019 struct key *key; 1019 struct key *key;
1020 int loop, keep, max; 1020 int loop, keep, max;
1021 1021
1022 kenter("%x", key_serial(keyring)); 1022 kenter("{%x,%s}", key_serial(keyring), keyring->description);
1023 1023
1024 down_write(&keyring->sem); 1024 down_write(&keyring->sem);
1025 1025
1026 klist = keyring->payload.subscriptions; 1026 klist = keyring->payload.subscriptions;
1027 if (!klist) 1027 if (!klist)
1028 goto just_return; 1028 goto no_klist;
1029 1029
1030 /* work out how many subscriptions we're keeping */ 1030 /* work out how many subscriptions we're keeping */
1031 keep = 0; 1031 keep = 0;
1032 for (loop = klist->nkeys - 1; loop >= 0; loop--) 1032 for (loop = klist->nkeys - 1; loop >= 0; loop--)
1033 if (!key_is_dead(klist->keys[loop], limit)); 1033 if (!key_is_dead(klist->keys[loop], limit))
1034 keep++; 1034 keep++;
1035 1035
1036 if (keep == klist->nkeys) 1036 if (keep == klist->nkeys)
@@ -1041,7 +1041,7 @@ void keyring_gc(struct key *keyring, time_t limit)
1041 new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), 1041 new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
1042 GFP_KERNEL); 1042 GFP_KERNEL);
1043 if (!new) 1043 if (!new)
1044 goto just_return; 1044 goto nomem;
1045 new->maxkeys = max; 1045 new->maxkeys = max;
1046 new->nkeys = 0; 1046 new->nkeys = 0;
1047 new->delkey = 0; 1047 new->delkey = 0;
@@ -1081,7 +1081,21 @@ void keyring_gc(struct key *keyring, time_t limit)
1081discard_new: 1081discard_new:
1082 new->nkeys = keep; 1082 new->nkeys = keep;
1083 keyring_clear_rcu_disposal(&new->rcu); 1083 keyring_clear_rcu_disposal(&new->rcu);
1084 up_write(&keyring->sem);
1085 kleave(" [discard]");
1086 return;
1087
1084just_return: 1088just_return:
1085 up_write(&keyring->sem); 1089 up_write(&keyring->sem);
1086 kleave(" [no]"); 1090 kleave(" [no dead]");
1091 return;
1092
1093no_klist:
1094 up_write(&keyring->sem);
1095 kleave(" [no_klist]");
1096 return;
1097
1098nomem:
1099 up_write(&keyring->sem);
1100 kleave(" [oom]");
1087} 1101}