Skip to content

Commit f771fde

Browse files
committed
keys: Simplify key description management
Simplify key description management by cramming the word containing the length with the first few chars of the description also. This simplifies the code that generates the index-key used by assoc_array. It should speed up key searching a bit too. Signed-off-by: David Howells <[email protected]>
1 parent 3b8c4a0 commit f771fde

File tree

5 files changed

+43
-50
lines changed

5 files changed

+43
-50
lines changed

include/linux/key.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,20 @@ struct keyring_list;
8686
struct keyring_name;
8787

8888
struct keyring_index_key {
89+
union {
90+
struct {
91+
#ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */
92+
u8 desc_len;
93+
char desc[sizeof(long) - 1]; /* First few chars of description */
94+
#else
95+
char desc[sizeof(long) - 1]; /* First few chars of description */
96+
u8 desc_len;
97+
#endif
98+
};
99+
unsigned long x;
100+
};
89101
struct key_type *type;
90102
const char *description;
91-
size_t desc_len;
92103
};
93104

94105
union key_payload {
@@ -202,6 +213,7 @@ struct key {
202213
union {
203214
struct keyring_index_key index_key;
204215
struct {
216+
unsigned long len_desc;
205217
struct key_type *type; /* type of key */
206218
char *description;
207219
};

security/keys/internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ extern struct mutex key_construction_mutex;
9090
extern wait_queue_head_t request_key_conswq;
9191

9292

93+
static inline void key_set_index_key(struct keyring_index_key *index_key)
94+
{
95+
size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
96+
memcpy(index_key->desc, index_key->description, n);
97+
}
98+
9399
extern struct key_type *key_type_lookup(const char *type);
94100
extern void key_type_put(struct key_type *ktype);
95101

security/keys/key.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
285285
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
286286
if (!key->index_key.description)
287287
goto no_memory_3;
288+
key_set_index_key(&key->index_key);
288289

289290
refcount_set(&key->usage, 1);
290291
init_rwsem(&key->sem);
@@ -868,6 +869,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
868869
goto error_free_prep;
869870
}
870871
index_key.desc_len = strlen(index_key.description);
872+
key_set_index_key(&index_key);
871873

872874
ret = __key_link_lock(keyring, &index_key);
873875
if (ret < 0) {

security/keys/keyring.c

Lines changed: 21 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde
179179
int n, desc_len = index_key->desc_len;
180180

181181
type = (unsigned long)index_key->type;
182-
183182
acc = mult_64x32_and_fold(type, desc_len + 13);
184183
acc = mult_64x32_and_fold(acc, 9207);
184+
185185
for (;;) {
186186
n = desc_len;
187187
if (n <= 0)
@@ -215,57 +215,37 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde
215215
/*
216216
* Build the next index key chunk.
217217
*
218-
* On 32-bit systems the index key is laid out as:
219-
*
220-
* 0 4 5 9...
221-
* hash desclen typeptr desc[]
222-
*
223-
* On 64-bit systems:
224-
*
225-
* 0 8 9 17...
226-
* hash desclen typeptr desc[]
227-
*
228218
* We return it one word-sized chunk at a time.
229219
*/
230220
static unsigned long keyring_get_key_chunk(const void *data, int level)
231221
{
232222
const struct keyring_index_key *index_key = data;
233223
unsigned long chunk = 0;
234-
long offset = 0;
224+
const u8 *d;
235225
int desc_len = index_key->desc_len, n = sizeof(chunk);
236226

237227
level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
238228
switch (level) {
239229
case 0:
240230
return hash_key_type_and_desc(index_key);
241231
case 1:
242-
return ((unsigned long)index_key->type << 8) | desc_len;
232+
return index_key->x;
243233
case 2:
244-
if (desc_len == 0)
245-
return (u8)((unsigned long)index_key->type >>
246-
(ASSOC_ARRAY_KEY_CHUNK_SIZE - 8));
247-
n--;
248-
offset = 1;
249-
/* fall through */
234+
return (unsigned long)index_key->type;
250235
default:
251-
offset += sizeof(chunk) - 1;
252-
offset += (level - 3) * sizeof(chunk);
253-
if (offset >= desc_len)
236+
level -= 3;
237+
if (desc_len <= sizeof(index_key->desc))
254238
return 0;
255-
desc_len -= offset;
239+
240+
d = index_key->description + sizeof(index_key->desc);
241+
d += level * sizeof(long);
242+
desc_len -= sizeof(index_key->desc);
256243
if (desc_len > n)
257244
desc_len = n;
258-
offset += desc_len;
259245
do {
260246
chunk <<= 8;
261-
chunk |= ((u8*)index_key->description)[--offset];
247+
chunk |= *d++;
262248
} while (--desc_len > 0);
263-
264-
if (level == 2) {
265-
chunk <<= 8;
266-
chunk |= (u8)((unsigned long)index_key->type >>
267-
(ASSOC_ARRAY_KEY_CHUNK_SIZE - 8));
268-
}
269249
return chunk;
270250
}
271251
}
@@ -304,39 +284,28 @@ static int keyring_diff_objects(const void *object, const void *data)
304284
seg_b = hash_key_type_and_desc(b);
305285
if ((seg_a ^ seg_b) != 0)
306286
goto differ;
287+
level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;
307288

308289
/* The number of bits contributed by the hash is controlled by a
309290
* constant in the assoc_array headers. Everything else thereafter we
310291
* can deal with as being machine word-size dependent.
311292
*/
312-
level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;
313-
seg_a = a->desc_len;
314-
seg_b = b->desc_len;
293+
seg_a = a->x;
294+
seg_b = b->x;
315295
if ((seg_a ^ seg_b) != 0)
316296
goto differ;
297+
level += sizeof(unsigned long);
317298

318299
/* The next bit may not work on big endian */
319-
level++;
320300
seg_a = (unsigned long)a->type;
321301
seg_b = (unsigned long)b->type;
322302
if ((seg_a ^ seg_b) != 0)
323303
goto differ;
324-
325304
level += sizeof(unsigned long);
326-
if (a->desc_len == 0)
327-
goto same;
328305

329-
i = 0;
330-
if (((unsigned long)a->description | (unsigned long)b->description) &
331-
(sizeof(unsigned long) - 1)) {
332-
do {
333-
seg_a = *(unsigned long *)(a->description + i);
334-
seg_b = *(unsigned long *)(b->description + i);
335-
if ((seg_a ^ seg_b) != 0)
336-
goto differ_plus_i;
337-
i += sizeof(unsigned long);
338-
} while (i < (a->desc_len & (sizeof(unsigned long) - 1)));
339-
}
306+
i = sizeof(a->desc);
307+
if (a->desc_len <= i)
308+
goto same;
340309

341310
for (; i < a->desc_len; i++) {
342311
seg_a = *(unsigned char *)(a->description + i);
@@ -662,6 +631,9 @@ static bool search_nested_keyrings(struct key *keyring,
662631
BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
663632
(ctx->flags & STATE_CHECKS) == STATE_CHECKS);
664633

634+
if (ctx->index_key.description)
635+
key_set_index_key(&ctx->index_key);
636+
665637
/* Check to see if this top-level keyring is what we are looking for
666638
* and whether it is valid or not.
667639
*/

security/keys/persistent.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
8787
index_key.type = &key_type_keyring;
8888
index_key.description = buf;
8989
index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid));
90+
key_set_index_key(&index_key);
9091

9192
if (ns->persistent_keyring_register) {
9293
reg_ref = make_key_ref(ns->persistent_keyring_register, true);

0 commit comments

Comments
 (0)