Skip to content

Commit 5007728

Browse files
WOnder93pcmoore
authored andcommitted
selinux: hash context structure directly
Always hashing the string representation is inefficient. Just hash the contents of the structure directly (using jhash). If the context is invalid (str & len are set), then hash the string as before, otherwise hash the structured data. Since the context hashing function is now faster (about 10 times), this patch decreases the overhead of security_transition_sid(), which is called from many hooks. The jhash function seemed as a good choice, since it is used as the default hashing algorithm in rhashtable. Signed-off-by: Ondrej Mosnacek <[email protected]> Reviewed-by: Jeff Vander Stoep <[email protected]> Tested-by: Jeff Vander Stoep <[email protected]> [PM: fixed some spelling errors in the comments pointed out by JVS] Signed-off-by: Paul Moore <[email protected]>
1 parent e67b2ec commit 5007728

File tree

9 files changed

+69
-42
lines changed

9 files changed

+69
-42
lines changed

security/selinux/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
88
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
99
netnode.o netport.o status.o \
1010
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
11-
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o
11+
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
1212

1313
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
1414

security/selinux/ss/context.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Implementations of the security context functions.
4+
*
5+
* Author: Ondrej Mosnacek <[email protected]>
6+
* Copyright (C) 2020 Red Hat, Inc.
7+
*/
8+
9+
#include <linux/jhash.h>
10+
11+
#include "context.h"
12+
#include "mls.h"
13+
14+
u32 context_compute_hash(const struct context *c)
15+
{
16+
u32 hash = 0;
17+
18+
/*
19+
* If a context is invalid, it will always be represented by a
20+
* context struct with only the len & str set (and vice versa)
21+
* under a given policy. Since context structs from different
22+
* policies should never meet, it is safe to hash valid and
23+
* invalid contexts differently. The context_cmp() function
24+
* already operates under the same assumption.
25+
*/
26+
if (c->len)
27+
return full_name_hash(NULL, c->str, c->len);
28+
29+
hash = jhash_3words(c->user, c->role, c->type, hash);
30+
hash = mls_range_hash(&c->range, hash);
31+
return hash;
32+
}

security/selinux/ss/context.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,11 @@ static inline int context_cmp(struct context *c1, struct context *c2)
196196
mls_context_cmp(c1, c2));
197197
}
198198

199-
static inline unsigned int context_compute_hash(const char *s)
199+
u32 context_compute_hash(const struct context *c);
200+
201+
static inline void context_add_hash(struct context *context)
200202
{
201-
return full_name_hash(NULL, s, strlen(s));
203+
context->hash = context_compute_hash(context);
202204
}
203205

204206
#endif /* _SS_CONTEXT_H_ */

security/selinux/ss/ebitmap.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/kernel.h>
2020
#include <linux/slab.h>
2121
#include <linux/errno.h>
22+
#include <linux/jhash.h>
2223
#include <net/netlabel.h>
2324
#include "ebitmap.h"
2425
#include "policydb.h"
@@ -542,6 +543,19 @@ int ebitmap_write(struct ebitmap *e, void *fp)
542543
return 0;
543544
}
544545

546+
u32 ebitmap_hash(const struct ebitmap *e, u32 hash)
547+
{
548+
struct ebitmap_node *node;
549+
550+
/* need to change hash even if ebitmap is empty */
551+
hash = jhash_1word(e->highbit, hash);
552+
for (node = e->node; node; node = node->next) {
553+
hash = jhash_1word(node->startbit, hash);
554+
hash = jhash(node->maps, sizeof(node->maps), hash);
555+
}
556+
return hash;
557+
}
558+
545559
void __init ebitmap_cache_init(void)
546560
{
547561
ebitmap_node_cachep = kmem_cache_create("ebitmap_node",

security/selinux/ss/ebitmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
131131
void ebitmap_destroy(struct ebitmap *e);
132132
int ebitmap_read(struct ebitmap *e, void *fp);
133133
int ebitmap_write(struct ebitmap *e, void *fp);
134+
u32 ebitmap_hash(const struct ebitmap *e, u32 hash);
134135

135136
#ifdef CONFIG_NETLABEL
136137
int ebitmap_netlbl_export(struct ebitmap *ebmap,

security/selinux/ss/mls.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
#ifndef _SS_MLS_H_
2323
#define _SS_MLS_H_
2424

25+
#include <linux/jhash.h>
26+
2527
#include "context.h"
28+
#include "ebitmap.h"
2629
#include "policydb.h"
2730

2831
int mls_compute_context_len(struct policydb *p, struct context *context);
@@ -101,5 +104,13 @@ static inline int mls_import_netlbl_cat(struct policydb *p,
101104
}
102105
#endif
103106

107+
static inline u32 mls_range_hash(const struct mls_range *r, u32 hash)
108+
{
109+
hash = jhash_2words(r->level[0].sens, r->level[1].sens, hash);
110+
hash = ebitmap_hash(&r->level[0].cat, hash);
111+
hash = ebitmap_hash(&r->level[1].cat, hash);
112+
return hash;
113+
}
114+
104115
#endif /* _SS_MLS_H */
105116

security/selinux/ss/policydb.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -862,11 +862,8 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
862862
if (!name)
863863
continue;
864864

865-
rc = context_add_hash(p, &c->context[0]);
866-
if (rc) {
867-
sidtab_destroy(s);
868-
goto out;
869-
}
865+
context_add_hash(&c->context[0]);
866+
870867
rc = sidtab_set_initial(s, sid, &c->context[0]);
871868
if (rc) {
872869
pr_err("SELinux: unable to load initial SID %s.\n",

security/selinux/ss/services.c

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,38 +1490,13 @@ static int string_to_context_struct(struct policydb *pol,
14901490
return rc;
14911491
}
14921492

1493-
int context_add_hash(struct policydb *policydb,
1494-
struct context *context)
1495-
{
1496-
int rc;
1497-
char *str;
1498-
int len;
1499-
1500-
if (context->str) {
1501-
context->hash = context_compute_hash(context->str);
1502-
} else {
1503-
rc = context_struct_to_string(policydb, context,
1504-
&str, &len);
1505-
if (rc)
1506-
return rc;
1507-
context->hash = context_compute_hash(str);
1508-
kfree(str);
1509-
}
1510-
return 0;
1511-
}
1512-
15131493
static int context_struct_to_sid(struct selinux_state *state,
15141494
struct context *context, u32 *sid)
15151495
{
1516-
int rc;
15171496
struct sidtab *sidtab = state->ss->sidtab;
1518-
struct policydb *policydb = &state->ss->policydb;
15191497

1520-
if (!context->hash) {
1521-
rc = context_add_hash(policydb, context);
1522-
if (rc)
1523-
return rc;
1524-
}
1498+
if (!context->hash)
1499+
context_add_hash(context);
15251500

15261501
return sidtab_context_to_sid(sidtab, context, sid);
15271502
}
@@ -2119,9 +2094,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p)
21192094
goto bad;
21202095
}
21212096

2122-
rc = context_add_hash(args->newp, newc);
2123-
if (rc)
2124-
goto bad;
2097+
context_add_hash(newc);
21252098

21262099
return 0;
21272100
bad:
@@ -2132,7 +2105,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p)
21322105
context_destroy(newc);
21332106
newc->str = s;
21342107
newc->len = len;
2135-
newc->hash = context_compute_hash(s);
2108+
context_add_hash(newc);
21362109
pr_info("SELinux: Context %s became invalid (unmapped).\n",
21372110
newc->str);
21382111
return 0;

security/selinux/ss/services.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#define _SS_SERVICES_H_
99

1010
#include "policydb.h"
11-
#include "context.h"
1211

1312
/* Mapping for a single class */
1413
struct selinux_mapping {
@@ -37,6 +36,4 @@ void services_compute_xperms_drivers(struct extended_perms *xperms,
3736
void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
3837
struct avtab_node *node);
3938

40-
int context_add_hash(struct policydb *policydb, struct context *context);
41-
4239
#endif /* _SS_SERVICES_H_ */

0 commit comments

Comments
 (0)