Skip to content

Commit 97be1e8

Browse files
dhowellsgregkh
authored andcommitted
keys, dns: Allow key types (eg. DNS) to be reclaimed immediately on expiry
[ Upstream commit 39299bd ] If a key has an expiration time, then when that time passes, the key is left around for a certain amount of time before being collected (5 mins by default) so that EKEYEXPIRED can be returned instead of ENOKEY. This is a problem for DNS keys because we want to redo the DNS lookup immediately at that point. Fix this by allowing key types to be marked such that keys of that type don't have this extra period, but are reclaimed as soon as they expire and turn this on for dns_resolver-type keys. To make this easier to handle, key->expiry is changed to be permanent if TIME64_MAX rather than 0. Furthermore, give such new-style negative DNS results a 1s default expiry if no other expiry time is set rather than allowing it to stick around indefinitely. This shouldn't be zero as ls will follow a failing stat call immediately with a second with AT_SYMLINK_NOFOLLOW added. Fixes: 1a4240f ("DNS: Separate out CIFS DNS Resolver code") Signed-off-by: David Howells <[email protected]> Tested-by: Markus Suvanto <[email protected]> cc: Wang Lei <[email protected]> cc: Jeff Layton <[email protected]> cc: Steve French <[email protected]> cc: Marc Dionne <[email protected]> cc: Jarkko Sakkinen <[email protected]> cc: "David S. Miller" <[email protected]> cc: Eric Dumazet <[email protected]> cc: Jakub Kicinski <[email protected]> cc: Paolo Abeni <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent 9e0d18f commit 97be1e8

File tree

6 files changed

+47
-23
lines changed

6 files changed

+47
-23
lines changed

include/linux/key-type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct key_type {
7272

7373
unsigned int flags;
7474
#define KEY_TYPE_NET_DOMAIN 0x00000001 /* Keys of this type have a net namespace domain */
75+
#define KEY_TYPE_INSTANT_REAP 0x00000002 /* Keys of this type don't have a delay after expiring */
7576

7677
/* vet a description */
7778
int (*vet_description)(const char *description);

net/dns_resolver/dns_key.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const struct cred *dns_resolver_cache;
9191
static int
9292
dns_resolver_preparse(struct key_preparsed_payload *prep)
9393
{
94+
const struct dns_server_list_v1_header *v1;
9495
const struct dns_payload_header *bin;
9596
struct user_key_payload *upayload;
9697
unsigned long derrno;
@@ -122,6 +123,13 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
122123
return -EINVAL;
123124
}
124125

126+
v1 = (const struct dns_server_list_v1_header *)bin;
127+
if ((v1->status != DNS_LOOKUP_GOOD &&
128+
v1->status != DNS_LOOKUP_GOOD_WITH_BAD)) {
129+
if (prep->expiry == TIME64_MAX)
130+
prep->expiry = ktime_get_real_seconds() + 1;
131+
}
132+
125133
result_len = datalen;
126134
goto store_result;
127135
}
@@ -314,7 +322,7 @@ static long dns_resolver_read(const struct key *key,
314322

315323
struct key_type key_type_dns_resolver = {
316324
.name = "dns_resolver",
317-
.flags = KEY_TYPE_NET_DOMAIN,
325+
.flags = KEY_TYPE_NET_DOMAIN | KEY_TYPE_INSTANT_REAP,
318326
.preparse = dns_resolver_preparse,
319327
.free_preparse = dns_resolver_free_preparse,
320328
.instantiate = generic_key_instantiate,

security/keys/gc.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@ void key_schedule_gc(time64_t gc_at)
6666
}
6767
}
6868

69+
/*
70+
* Set the expiration time on a key.
71+
*/
72+
void key_set_expiry(struct key *key, time64_t expiry)
73+
{
74+
key->expiry = expiry;
75+
if (expiry != TIME64_MAX) {
76+
if (!(key->type->flags & KEY_TYPE_INSTANT_REAP))
77+
expiry += key_gc_delay;
78+
key_schedule_gc(expiry);
79+
}
80+
}
81+
6982
/*
7083
* Schedule a dead links collection run.
7184
*/
@@ -176,29 +189,24 @@ static void key_garbage_collector(struct work_struct *work)
176189
static u8 gc_state; /* Internal persistent state */
177190
#define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */
178191
#define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */
179-
#define KEY_GC_SET_TIMER 0x04 /* - We need to restart the timer */
180192
#define KEY_GC_REAPING_DEAD_1 0x10 /* - We need to mark dead keys */
181193
#define KEY_GC_REAPING_DEAD_2 0x20 /* - We need to reap dead key links */
182194
#define KEY_GC_REAPING_DEAD_3 0x40 /* - We need to reap dead keys */
183195
#define KEY_GC_FOUND_DEAD_KEY 0x80 /* - We found at least one dead key */
184196

185197
struct rb_node *cursor;
186198
struct key *key;
187-
time64_t new_timer, limit;
199+
time64_t new_timer, limit, expiry;
188200

189201
kenter("[%lx,%x]", key_gc_flags, gc_state);
190202

191203
limit = ktime_get_real_seconds();
192-
if (limit > key_gc_delay)
193-
limit -= key_gc_delay;
194-
else
195-
limit = key_gc_delay;
196204

197205
/* Work out what we're going to be doing in this pass */
198206
gc_state &= KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2;
199207
gc_state <<= 1;
200208
if (test_and_clear_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags))
201-
gc_state |= KEY_GC_REAPING_LINKS | KEY_GC_SET_TIMER;
209+
gc_state |= KEY_GC_REAPING_LINKS;
202210

203211
if (test_and_clear_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags))
204212
gc_state |= KEY_GC_REAPING_DEAD_1;
@@ -233,8 +241,11 @@ static void key_garbage_collector(struct work_struct *work)
233241
}
234242
}
235243

236-
if (gc_state & KEY_GC_SET_TIMER) {
237-
if (key->expiry > limit && key->expiry < new_timer) {
244+
expiry = key->expiry;
245+
if (expiry != TIME64_MAX) {
246+
if (!(key->type->flags & KEY_TYPE_INSTANT_REAP))
247+
expiry += key_gc_delay;
248+
if (expiry > limit && expiry < new_timer) {
238249
kdebug("will expire %x in %lld",
239250
key_serial(key), key->expiry - limit);
240251
new_timer = key->expiry;
@@ -276,7 +287,7 @@ static void key_garbage_collector(struct work_struct *work)
276287
*/
277288
kdebug("pass complete");
278289

279-
if (gc_state & KEY_GC_SET_TIMER && new_timer != (time64_t)TIME64_MAX) {
290+
if (new_timer != TIME64_MAX) {
280291
new_timer += key_gc_delay;
281292
key_schedule_gc(new_timer);
282293
}

security/keys/internal.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ extern unsigned key_gc_delay;
176176
extern void keyring_gc(struct key *keyring, time64_t limit);
177177
extern void keyring_restriction_gc(struct key *keyring,
178178
struct key_type *dead_type);
179+
void key_set_expiry(struct key *key, time64_t expiry);
179180
extern void key_schedule_gc(time64_t gc_at);
180181
extern void key_schedule_gc_links(void);
181182
extern void key_gc_keytype(struct key_type *ktype);
@@ -224,10 +225,18 @@ extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
224225
*/
225226
static inline bool key_is_dead(const struct key *key, time64_t limit)
226227
{
228+
time64_t expiry = key->expiry;
229+
230+
if (expiry != TIME64_MAX) {
231+
if (!(key->type->flags & KEY_TYPE_INSTANT_REAP))
232+
expiry += key_gc_delay;
233+
if (expiry <= limit)
234+
return true;
235+
}
236+
227237
return
228238
key->flags & ((1 << KEY_FLAG_DEAD) |
229239
(1 << KEY_FLAG_INVALIDATED)) ||
230-
(key->expiry > 0 && key->expiry <= limit) ||
231240
key->domain_tag->removed;
232241
}
233242

security/keys/key.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
294294
key->uid = uid;
295295
key->gid = gid;
296296
key->perm = perm;
297+
key->expiry = TIME64_MAX;
297298
key->restrict_link = restrict_link;
298299
key->last_used_at = ktime_get_real_seconds();
299300

@@ -463,10 +464,7 @@ static int __key_instantiate_and_link(struct key *key,
463464
if (authkey)
464465
key_invalidate(authkey);
465466

466-
if (prep->expiry != TIME64_MAX) {
467-
key->expiry = prep->expiry;
468-
key_schedule_gc(prep->expiry + key_gc_delay);
469-
}
467+
key_set_expiry(key, prep->expiry);
470468
}
471469
}
472470

@@ -605,8 +603,7 @@ int key_reject_and_link(struct key *key,
605603
atomic_inc(&key->user->nikeys);
606604
mark_key_instantiated(key, -error);
607605
notify_key(key, NOTIFY_KEY_INSTANTIATED, -error);
608-
key->expiry = ktime_get_real_seconds() + timeout;
609-
key_schedule_gc(key->expiry + key_gc_delay);
606+
key_set_expiry(key, ktime_get_real_seconds() + timeout);
610607

611608
if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
612609
awaken = 1;
@@ -721,16 +718,14 @@ struct key_type *key_type_lookup(const char *type)
721718

722719
void key_set_timeout(struct key *key, unsigned timeout)
723720
{
724-
time64_t expiry = 0;
721+
time64_t expiry = TIME64_MAX;
725722

726723
/* make the changes with the locks held to prevent races */
727724
down_write(&key->sem);
728725

729726
if (timeout > 0)
730727
expiry = ktime_get_real_seconds() + timeout;
731-
732-
key->expiry = expiry;
733-
key_schedule_gc(key->expiry + key_gc_delay);
728+
key_set_expiry(key, expiry);
734729

735730
up_write(&key->sem);
736731
}

security/keys/proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
198198

199199
/* come up with a suitable timeout value */
200200
expiry = READ_ONCE(key->expiry);
201-
if (expiry == 0) {
201+
if (expiry == TIME64_MAX) {
202202
memcpy(xbuf, "perm", 5);
203203
} else if (now >= expiry) {
204204
memcpy(xbuf, "expd", 5);

0 commit comments

Comments
 (0)