Skip to content

Commit b2a4df2

Browse files
committed
KEYS: Expand the capacity of a keyring
Expand the capacity of a keyring to be able to hold a lot more keys by using the previously added associative array implementation. Currently the maximum capacity is: (PAGE_SIZE - sizeof(header)) / sizeof(struct key *) which, on a 64-bit system, is a little more 500. However, since this is being used for the NFS uid mapper, we need more than that. The new implementation gives us effectively unlimited capacity. With some alterations, the keyutils testsuite runs successfully to completion after this patch is applied. The alterations are because (a) keyrings that are simply added to no longer appear ordered and (b) some of the errors have changed a bit. Signed-off-by: David Howells <dhowells@redhat.com>
1 parent 3cb9895 commit b2a4df2

File tree

9 files changed

+803
-762
lines changed

9 files changed

+803
-762
lines changed

include/keys/keyring-type.h

+2-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Keyring key type
22
*
3-
* Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
3+
* Copyright (C) 2008, 2013 Red Hat, Inc. All Rights Reserved.
44
* Written by David Howells (dhowells@redhat.com)
55
*
66
* This program is free software; you can redistribute it and/or
@@ -13,19 +13,6 @@
1313
#define _KEYS_KEYRING_TYPE_H
1414

1515
#include <linux/key.h>
16-
#include <linux/rcupdate.h>
17-
18-
/*
19-
* the keyring payload contains a list of the keys to which the keyring is
20-
* subscribed
21-
*/
22-
struct keyring_list {
23-
struct rcu_head rcu; /* RCU deletion hook */
24-
unsigned short maxkeys; /* max keys this list can hold */
25-
unsigned short nkeys; /* number of keys currently held */
26-
unsigned short delkey; /* key to be unlinked by RCU */
27-
struct key __rcu *keys[0];
28-
};
29-
16+
#include <linux/assoc_array.h>
3017

3118
#endif /* _KEYS_KEYRING_TYPE_H */

include/linux/key.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/sysctl.h>
2323
#include <linux/rwsem.h>
2424
#include <linux/atomic.h>
25+
#include <linux/assoc_array.h>
2526

2627
#ifdef __KERNEL__
2728
#include <linux/uidgid.h>
@@ -196,11 +197,13 @@ struct key {
196197
* whatever
197198
*/
198199
union {
199-
unsigned long value;
200-
void __rcu *rcudata;
201-
void *data;
202-
struct keyring_list __rcu *subscriptions;
203-
} payload;
200+
union {
201+
unsigned long value;
202+
void __rcu *rcudata;
203+
void *data;
204+
} payload;
205+
struct assoc_array keys;
206+
};
204207
};
205208

206209
extern struct key *key_alloc(struct key_type *type,

lib/assoc_array.c

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
//#define DEBUG
1414
#include <linux/slab.h>
15+
#include <linux/err.h>
1516
#include <linux/assoc_array_priv.h>
1617

1718
/*

security/keys/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
config KEYS
66
bool "Enable access key retention support"
7+
select ASSOCIATIVE_ARRAY
78
help
89
This option provides support for retaining authentication tokens and
910
access keys in the kernel.

security/keys/gc.c

+14-19
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ void key_gc_keytype(struct key_type *ktype)
130130
kleave("");
131131
}
132132

133+
static int key_gc_keyring_func(const void *object, void *iterator_data)
134+
{
135+
const struct key *key = object;
136+
time_t *limit = iterator_data;
137+
return key_is_dead(key, *limit);
138+
}
139+
133140
/*
134141
* Garbage collect pointers from a keyring.
135142
*
@@ -138,38 +145,27 @@ void key_gc_keytype(struct key_type *ktype)
138145
*/
139146
static void key_gc_keyring(struct key *keyring, time_t limit)
140147
{
141-
struct keyring_list *klist;
142-
int loop;
148+
int result;
143149

144-
kenter("%x", key_serial(keyring));
150+
kenter("%x{%s}", keyring->serial, keyring->description ?: "");
145151

146152
if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
147153
(1 << KEY_FLAG_REVOKED)))
148154
goto dont_gc;
149155

150156
/* scan the keyring looking for dead keys */
151157
rcu_read_lock();
152-
klist = rcu_dereference(keyring->payload.subscriptions);
153-
if (!klist)
154-
goto unlock_dont_gc;
155-
156-
loop = klist->nkeys;
157-
smp_rmb();
158-
for (loop--; loop >= 0; loop--) {
159-
struct key *key = rcu_dereference(klist->keys[loop]);
160-
if (key_is_dead(key, limit))
161-
goto do_gc;
162-
}
163-
164-
unlock_dont_gc:
158+
result = assoc_array_iterate(&keyring->keys,
159+
key_gc_keyring_func, &limit);
165160
rcu_read_unlock();
161+
if (result == true)
162+
goto do_gc;
163+
166164
dont_gc:
167165
kleave(" [no gc]");
168166
return;
169167

170168
do_gc:
171-
rcu_read_unlock();
172-
173169
keyring_gc(keyring, limit);
174170
kleave(" [gc]");
175171
}
@@ -392,7 +388,6 @@ static void key_garbage_collector(struct work_struct *work)
392388
*/
393389
found_keyring:
394390
spin_unlock(&key_serial_lock);
395-
kdebug("scan keyring %d", key->serial);
396391
key_gc_keyring(key, limit);
397392
goto maybe_resched;
398393

security/keys/internal.h

+11-6
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,23 @@ extern void key_type_put(struct key_type *ktype);
9090

9191
extern int __key_link_begin(struct key *keyring,
9292
const struct keyring_index_key *index_key,
93-
unsigned long *_prealloc);
93+
struct assoc_array_edit **_edit);
9494
extern int __key_link_check_live_key(struct key *keyring, struct key *key);
95-
extern void __key_link(struct key *keyring, struct key *key,
96-
unsigned long *_prealloc);
95+
extern void __key_link(struct key *key, struct assoc_array_edit **_edit);
9796
extern void __key_link_end(struct key *keyring,
9897
const struct keyring_index_key *index_key,
99-
unsigned long prealloc);
98+
struct assoc_array_edit *edit);
10099

101-
extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
102-
const struct keyring_index_key *index_key);
100+
extern key_ref_t find_key_to_update(key_ref_t keyring_ref,
101+
const struct keyring_index_key *index_key);
103102

104103
extern struct key *keyring_search_instkey(struct key *keyring,
105104
key_serial_t target_id);
106105

106+
extern int iterate_over_keyring(const struct key *keyring,
107+
int (*func)(const struct key *key, void *data),
108+
void *data);
109+
107110
typedef int (*key_match_func_t)(const struct key *, const void *);
108111

109112
struct keyring_search_context {
@@ -119,6 +122,8 @@ struct keyring_search_context {
119122
#define KEYRING_SEARCH_NO_CHECK_PERM 0x0010 /* Don't check permissions */
120123
#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0020 /* Give an error on excessive depth */
121124

125+
int (*iterator)(const void *object, void *iterator_data);
126+
122127
/* Internal stuff */
123128
int skipped_ret;
124129
bool possessed;

security/keys/key.c

+17-18
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ static int __key_instantiate_and_link(struct key *key,
409409
struct key_preparsed_payload *prep,
410410
struct key *keyring,
411411
struct key *authkey,
412-
unsigned long *_prealloc)
412+
struct assoc_array_edit **_edit)
413413
{
414414
int ret, awaken;
415415

@@ -436,7 +436,7 @@ static int __key_instantiate_and_link(struct key *key,
436436

437437
/* and link it into the destination keyring */
438438
if (keyring)
439-
__key_link(keyring, key, _prealloc);
439+
__key_link(key, _edit);
440440

441441
/* disable the authorisation key */
442442
if (authkey)
@@ -476,7 +476,7 @@ int key_instantiate_and_link(struct key *key,
476476
struct key *authkey)
477477
{
478478
struct key_preparsed_payload prep;
479-
unsigned long prealloc;
479+
struct assoc_array_edit *edit;
480480
int ret;
481481

482482
memset(&prep, 0, sizeof(prep));
@@ -490,16 +490,15 @@ int key_instantiate_and_link(struct key *key,
490490
}
491491

492492
if (keyring) {
493-
ret = __key_link_begin(keyring, &key->index_key, &prealloc);
493+
ret = __key_link_begin(keyring, &key->index_key, &edit);
494494
if (ret < 0)
495495
goto error_free_preparse;
496496
}
497497

498-
ret = __key_instantiate_and_link(key, &prep, keyring, authkey,
499-
&prealloc);
498+
ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
500499

501500
if (keyring)
502-
__key_link_end(keyring, &key->index_key, prealloc);
501+
__key_link_end(keyring, &key->index_key, edit);
503502

504503
error_free_preparse:
505504
if (key->type->preparse)
@@ -537,7 +536,7 @@ int key_reject_and_link(struct key *key,
537536
struct key *keyring,
538537
struct key *authkey)
539538
{
540-
unsigned long prealloc;
539+
struct assoc_array_edit *edit;
541540
struct timespec now;
542541
int ret, awaken, link_ret = 0;
543542

@@ -548,7 +547,7 @@ int key_reject_and_link(struct key *key,
548547
ret = -EBUSY;
549548

550549
if (keyring)
551-
link_ret = __key_link_begin(keyring, &key->index_key, &prealloc);
550+
link_ret = __key_link_begin(keyring, &key->index_key, &edit);
552551

553552
mutex_lock(&key_construction_mutex);
554553

@@ -570,7 +569,7 @@ int key_reject_and_link(struct key *key,
570569

571570
/* and link it into the destination keyring */
572571
if (keyring && link_ret == 0)
573-
__key_link(keyring, key, &prealloc);
572+
__key_link(key, &edit);
574573

575574
/* disable the authorisation key */
576575
if (authkey)
@@ -580,7 +579,7 @@ int key_reject_and_link(struct key *key,
580579
mutex_unlock(&key_construction_mutex);
581580

582581
if (keyring)
583-
__key_link_end(keyring, &key->index_key, prealloc);
582+
__key_link_end(keyring, &key->index_key, edit);
584583

585584
/* wake up anyone waiting for a key to be constructed */
586585
if (awaken)
@@ -783,8 +782,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
783782
.description = description,
784783
};
785784
struct key_preparsed_payload prep;
785+
struct assoc_array_edit *edit;
786786
const struct cred *cred = current_cred();
787-
unsigned long prealloc;
788787
struct key *keyring, *key = NULL;
789788
key_ref_t key_ref;
790789
int ret;
@@ -828,7 +827,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
828827
}
829828
index_key.desc_len = strlen(index_key.description);
830829

831-
ret = __key_link_begin(keyring, &index_key, &prealloc);
830+
ret = __key_link_begin(keyring, &index_key, &edit);
832831
if (ret < 0) {
833832
key_ref = ERR_PTR(ret);
834833
goto error_free_prep;
@@ -847,8 +846,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
847846
* update that instead if possible
848847
*/
849848
if (index_key.type->update) {
850-
key_ref = __keyring_search_one(keyring_ref, &index_key);
851-
if (!IS_ERR(key_ref))
849+
key_ref = find_key_to_update(keyring_ref, &index_key);
850+
if (key_ref)
852851
goto found_matching_key;
853852
}
854853

@@ -874,7 +873,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
874873
}
875874

876875
/* instantiate it and link it into the target keyring */
877-
ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
876+
ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &edit);
878877
if (ret < 0) {
879878
key_put(key);
880879
key_ref = ERR_PTR(ret);
@@ -884,7 +883,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
884883
key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
885884

886885
error_link_end:
887-
__key_link_end(keyring, &index_key, prealloc);
886+
__key_link_end(keyring, &index_key, edit);
888887
error_free_prep:
889888
if (index_key.type->preparse)
890889
index_key.type->free_preparse(&prep);
@@ -897,7 +896,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
897896
/* we found a matching key, so we're going to try to update it
898897
* - we can drop the locks first as we have the key pinned
899898
*/
900-
__key_link_end(keyring, &index_key, prealloc);
899+
__key_link_end(keyring, &index_key, edit);
901900

902901
key_ref = __key_update(key_ref, &prep);
903902
goto error_free_prep;

0 commit comments

Comments
 (0)