Skip to content

Commit e0ac568

Browse files
WOnder93pcmoore
authored andcommitted
selinux: reduce the use of hard-coded hash sizes
Instead allocate hash tables with just the right size based on the actual number of elements (which is almost always known beforehand, we just need to defer the hashtab allocation to the right time). The only case when we don't know the size (with the current policy format) is the new filename transitions hashtable. Here I just left the existing value. After this patch, the time to load Fedora policy on x86_64 decreases from 790 ms to 167 ms. If the unconfined module is removed, it decreases from 750 ms to 122 ms. It is also likely that other operations are going to be faster, mainly string_to_context_struct() or mls_compute_sid(), but I didn't try to quantify that. The memory usage of all hash table arrays increases from ~58 KB to ~163 KB (with Fedora policy on x86_64). Signed-off-by: Ondrej Mosnacek <[email protected]> Acked-by: Stephen Smalley <[email protected]> Signed-off-by: Paul Moore <[email protected]>
1 parent e4cfa05 commit e0ac568

File tree

4 files changed

+45
-40
lines changed

4 files changed

+45
-40
lines changed

security/selinux/ss/hashtab.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,29 @@
1212

1313
static struct kmem_cache *hashtab_node_cachep;
1414

15+
/*
16+
* Here we simply round the number of elements up to the nearest power of two.
17+
* I tried also other options like rouding down or rounding to the closest
18+
* power of two (up or down based on which is closer), but I was unable to
19+
* find any significant difference in lookup/insert performance that would
20+
* justify switching to a different (less intuitive) formula. It could be that
21+
* a different formula is actually more optimal, but any future changes here
22+
* should be supported with performance/memory usage data.
23+
*
24+
* The total memory used by the htable arrays (only) with Fedora policy loaded
25+
* is approximately 163 KB at the time of writing.
26+
*/
27+
static u32 hashtab_compute_size(u32 nel)
28+
{
29+
return nel == 0 ? 0 : roundup_pow_of_two(nel);
30+
}
31+
1532
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
1633
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
17-
u32 size)
34+
u32 nel_hint)
1835
{
1936
struct hashtab *p;
20-
u32 i;
37+
u32 i, size = hashtab_compute_size(nel_hint);
2138

2239
p = kzalloc(sizeof(*p), GFP_KERNEL);
2340
if (!p)
@@ -27,6 +44,9 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *
2744
p->nel = 0;
2845
p->hash_value = hash_value;
2946
p->keycmp = keycmp;
47+
if (!size)
48+
return p;
49+
3050
p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL);
3151
if (!p->htable) {
3252
kfree(p);
@@ -46,7 +66,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
4666

4767
cond_resched();
4868

49-
if (!h || h->nel == HASHTAB_MAX_NODES)
69+
if (!h || !h->size || h->nel == HASHTAB_MAX_NODES)
5070
return -EINVAL;
5171

5272
hvalue = h->hash_value(h, key);
@@ -82,7 +102,7 @@ void *hashtab_search(struct hashtab *h, const void *key)
82102
u32 hvalue;
83103
struct hashtab_node *cur;
84104

85-
if (!h)
105+
if (!h || !h->size)
86106
return NULL;
87107

88108
hvalue = h->hash_value(h, key);

security/selinux/ss/hashtab.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct hashtab_info {
4242
*/
4343
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
4444
int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
45-
u32 size);
45+
u32 nel_hint);
4646

4747
/*
4848
* Inserts the specified (key, datum) pair into the specified hash table.

security/selinux/ss/policydb.c

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,6 @@ static const char *symtab_name[SYM_NUM] = {
5656
};
5757
#endif
5858

59-
static unsigned int symtab_sizes[SYM_NUM] = {
60-
2,
61-
32,
62-
16,
63-
512,
64-
128,
65-
16,
66-
16,
67-
16,
68-
};
69-
7059
struct policydb_compat_info {
7160
int version;
7261
int sym_num;
@@ -478,20 +467,10 @@ static int policydb_init(struct policydb *p)
478467

479468
memset(p, 0, sizeof(*p));
480469

481-
for (i = 0; i < SYM_NUM; i++) {
482-
rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
483-
if (rc)
484-
goto out;
485-
}
486-
487470
rc = avtab_init(&p->te_avtab);
488471
if (rc)
489472
goto out;
490473

491-
rc = roles_init(p);
492-
if (rc)
493-
goto out;
494-
495474
rc = cond_policydb_init(p);
496475
if (rc)
497476
goto out;
@@ -503,20 +482,12 @@ static int policydb_init(struct policydb *p)
503482
goto out;
504483
}
505484

506-
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
507-
if (!p->range_tr) {
508-
rc = -ENOMEM;
509-
goto out;
510-
}
511-
512485
ebitmap_init(&p->filename_trans_ttypes);
513486
ebitmap_init(&p->policycaps);
514487
ebitmap_init(&p->permissive_map);
515488

516489
return 0;
517490
out:
518-
hashtab_destroy(p->filename_trans);
519-
hashtab_destroy(p->range_tr);
520491
for (i = 0; i < SYM_NUM; i++) {
521492
hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
522493
hashtab_destroy(p->symtab[i].table);
@@ -1142,12 +1113,12 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
11421113

11431114
len = le32_to_cpu(buf[0]);
11441115
comdatum->value = le32_to_cpu(buf[1]);
1116+
nel = le32_to_cpu(buf[3]);
11451117

1146-
rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
1118+
rc = symtab_init(&comdatum->permissions, nel);
11471119
if (rc)
11481120
goto bad;
11491121
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
1150-
nel = le32_to_cpu(buf[3]);
11511122

11521123
rc = str_read(&key, GFP_KERNEL, fp, len);
11531124
if (rc)
@@ -1308,12 +1279,12 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
13081279
len = le32_to_cpu(buf[0]);
13091280
len2 = le32_to_cpu(buf[1]);
13101281
cladatum->value = le32_to_cpu(buf[2]);
1282+
nel = le32_to_cpu(buf[4]);
13111283

1312-
rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
1284+
rc = symtab_init(&cladatum->permissions, nel);
13131285
if (rc)
13141286
goto bad;
13151287
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
1316-
nel = le32_to_cpu(buf[4]);
13171288

13181289
ncons = le32_to_cpu(buf[5]);
13191290

@@ -1826,6 +1797,11 @@ static int range_read(struct policydb *p, void *fp)
18261797
return rc;
18271798

18281799
nel = le32_to_cpu(buf[0]);
1800+
1801+
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, nel);
1802+
if (!p->range_tr)
1803+
return -ENOMEM;
1804+
18291805
for (i = 0; i < nel; i++) {
18301806
rc = -ENOMEM;
18311807
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
@@ -2418,6 +2394,17 @@ int policydb_read(struct policydb *p, void *fp)
24182394
goto bad;
24192395
nprim = le32_to_cpu(buf[0]);
24202396
nel = le32_to_cpu(buf[1]);
2397+
2398+
rc = symtab_init(&p->symtab[i], nel);
2399+
if (rc)
2400+
goto out;
2401+
2402+
if (i == SYM_ROLES) {
2403+
rc = roles_init(p);
2404+
if (rc)
2405+
goto out;
2406+
}
2407+
24212408
for (j = 0; j < nel; j++) {
24222409
rc = read_f[i](p, p->symtab[i].table, fp);
24232410
if (rc)

security/selinux/ss/policydb.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,6 @@ extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
321321
extern int policydb_read(struct policydb *p, void *fp);
322322
extern int policydb_write(struct policydb *p, void *fp);
323323

324-
#define PERM_SYMTAB_SIZE 32
325-
326324
#define POLICYDB_CONFIG_MLS 1
327325

328326
/* the config flags related to unknown classes/perms are bits 2 and 3 */

0 commit comments

Comments
 (0)