aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack
diff options
context:
space:
mode:
authorTomasz Stanislawski <t.stanislaws@samsung.com>2013-06-11 08:55:13 -0400
committerCasey Schaufler <casey@schaufler-ca.com>2013-08-01 19:55:20 -0400
commit4d7cf4a1f49f76f4069114ee08be75cd68c37c5a (patch)
treef57088bc8a93d2c1345eb8e50822f74dffff6350 /security/smack
parent470043ba995a79a274a5db306856975002a06f19 (diff)
security: smack: add a hash table to quicken smk_find_entry()
Accepted for the smack-next tree after changing the number of slots from 128 to 16. This patch adds a hash table to quicken searching of a smack label by its name. Basically, the patch improves performance of SMACK initialization. Parsing of rules involves translation from a string to a smack_known (aka label) entity which is done in smk_find_entry(). The current implementation of the function iterates over a global list of smack_known resulting in O(N) complexity for smk_find_entry(). The total complexity of SMACK initialization becomes O(rules * labels). Therefore it scales quadratically with a complexity of a system. Applying the patch reduced the complexity of smk_find_entry() to O(1) as long as number of label is in hundreds. If the number of labels is increased please update SMACK_HASH_SLOTS constant defined in security/smack/smack.h. Introducing the configuration of this constant with Kconfig or cmdline might be a good idea. The size of the hash table was adjusted experimentally. The rule set used by TIZEN contains circa 17K rules for 500 labels. The table above contains results of SMACK initialization using 'time smackctl apply' bash command. The 'Ref' is a kernel without this patch applied. The consecutive values refers to value of SMACK_HASH_SLOTS. Every measurement was repeated three times to reduce noise. | Ref | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 -------------------------------------------------------------------------------------------- Run1 | 1.156 | 1.096 | 0.883 | 0.764 | 0.692 | 0.667 | 0.649 | 0.633 | 0.634 | 0.629 | 0.620 Run2 | 1.156 | 1.111 | 0.885 | 0.764 | 0.694 | 0.661 | 0.649 | 0.651 | 0.634 | 0.638 | 0.623 Run3 | 1.160 | 1.107 | 0.886 | 0.764 | 0.694 | 0.671 | 0.661 | 0.638 | 0.631 | 0.624 | 0.638 AVG | 1.157 | 1.105 | 0.885 | 0.764 | 0.693 | 0.666 | 0.653 | 0.641 | 0.633 | 0.630 | 0.627 Surprisingly, a single hlist is slightly faster than a double-linked list. The speed-up saturates near 64 slots. Therefore I chose value 128 to provide some margin if more labels were used. It looks that IO becomes a new bottleneck. Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Diffstat (limited to 'security/smack')
-rw-r--r--security/smack/smack.h5
-rw-r--r--security/smack/smack_access.c29
-rw-r--r--security/smack/smack_lsm.c12
3 files changed, 37 insertions, 9 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 339614c76e63..e80597a3048a 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -53,6 +53,7 @@
53 */ 53 */
54struct smack_known { 54struct smack_known {
55 struct list_head list; 55 struct list_head list;
56 struct hlist_node smk_hashed;
56 char *smk_known; 57 char *smk_known;
57 u32 smk_secid; 58 u32 smk_secid;
58 struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ 59 struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
@@ -222,6 +223,7 @@ char *smk_parse_smack(const char *string, int len);
222int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); 223int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
223char *smk_import(const char *, int); 224char *smk_import(const char *, int);
224struct smack_known *smk_import_entry(const char *, int); 225struct smack_known *smk_import_entry(const char *, int);
226void smk_insert_entry(struct smack_known *skp);
225struct smack_known *smk_find_entry(const char *); 227struct smack_known *smk_find_entry(const char *);
226u32 smack_to_secid(const char *); 228u32 smack_to_secid(const char *);
227 229
@@ -247,6 +249,9 @@ extern struct list_head smk_netlbladdr_list;
247 249
248extern struct security_operations smack_ops; 250extern struct security_operations smack_ops;
249 251
252#define SMACK_HASH_SLOTS 16
253extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
254
250/* 255/*
251 * Is the directory transmuting? 256 * Is the directory transmuting?
252 */ 257 */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 6a0377f38620..b3b59b1e93d6 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -325,6 +325,25 @@ void smack_log(char *subject_label, char *object_label, int request,
325 325
326DEFINE_MUTEX(smack_known_lock); 326DEFINE_MUTEX(smack_known_lock);
327 327
328struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
329
330/**
331 * smk_insert_entry - insert a smack label into a hash map,
332 *
333 * this function must be called under smack_known_lock
334 */
335void smk_insert_entry(struct smack_known *skp)
336{
337 unsigned int hash;
338 struct hlist_head *head;
339
340 hash = full_name_hash(skp->smk_known, strlen(skp->smk_known));
341 head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
342
343 hlist_add_head_rcu(&skp->smk_hashed, head);
344 list_add_rcu(&skp->list, &smack_known_list);
345}
346
328/** 347/**
329 * smk_find_entry - find a label on the list, return the list entry 348 * smk_find_entry - find a label on the list, return the list entry
330 * @string: a text string that might be a Smack label 349 * @string: a text string that might be a Smack label
@@ -334,12 +353,16 @@ DEFINE_MUTEX(smack_known_lock);
334 */ 353 */
335struct smack_known *smk_find_entry(const char *string) 354struct smack_known *smk_find_entry(const char *string)
336{ 355{
356 unsigned int hash;
357 struct hlist_head *head;
337 struct smack_known *skp; 358 struct smack_known *skp;
338 359
339 list_for_each_entry_rcu(skp, &smack_known_list, list) { 360 hash = full_name_hash(string, strlen(string));
361 head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
362
363 hlist_for_each_entry_rcu(skp, head, smk_hashed)
340 if (strcmp(skp->smk_known, string) == 0) 364 if (strcmp(skp->smk_known, string) == 0)
341 return skp; 365 return skp;
342 }
343 366
344 return NULL; 367 return NULL;
345} 368}
@@ -475,7 +498,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
475 * Make sure that the entry is actually 498 * Make sure that the entry is actually
476 * filled before putting it on the list. 499 * filled before putting it on the list.
477 */ 500 */
478 list_add_rcu(&skp->list, &smack_known_list); 501 smk_insert_entry(skp);
479 goto unlockout; 502 goto unlockout;
480 } 503 }
481 /* 504 /*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3f7682a387b7..ce000a81caf7 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3879,12 +3879,12 @@ static __init void init_smack_known_list(void)
3879 /* 3879 /*
3880 * Create the known labels list 3880 * Create the known labels list
3881 */ 3881 */
3882 list_add(&smack_known_huh.list, &smack_known_list); 3882 smk_insert_entry(&smack_known_huh);
3883 list_add(&smack_known_hat.list, &smack_known_list); 3883 smk_insert_entry(&smack_known_hat);
3884 list_add(&smack_known_star.list, &smack_known_list); 3884 smk_insert_entry(&smack_known_star);
3885 list_add(&smack_known_floor.list, &smack_known_list); 3885 smk_insert_entry(&smack_known_floor);
3886 list_add(&smack_known_invalid.list, &smack_known_list); 3886 smk_insert_entry(&smack_known_invalid);
3887 list_add(&smack_known_web.list, &smack_known_list); 3887 smk_insert_entry(&smack_known_web);
3888} 3888}
3889 3889
3890/** 3890/**