Tuning avtab to reduce memory usage
PATCH 1/1 Tuning avtab to reduce memory usage
Hi.
I would like to propose patch that reduce memory usage of avtab again. It reduces number of hash slots of avtab.
Previous patch was discussed in past threads.
http://marc.info/?t=118517459600001&r=1&w=2
http://marc.info/?t=118526972800008&r=1&w=2
http://marc.info/?t=118647810000001&r=1&w=2
0. Background
* In avtab_init:
h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
Number of hash table size is AVTAB_SIZE.
* In avtab.h
#define AVTAB_HASH_BITS 15
#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
#define AVTAB_SIZE AVTAB_HASH_BUCKETS
AVTAB_SIZE is 2^15 = 32768
So 32768 entries are allocated for avtab,
and 2 avtabs are used in policydb:
struct avtab te_avtab;
struct avtab te_cond_avtab;
If te rules are fewer than 32768,
unused entries are using memory.
In embedded devices, the rules tend to be fewer.
In my test system(SH architecture board), it is less than 10000 rules. We want to save memory for embedded devices.
1. Explanation of patch
It decides number of hash slots dynamically based on number of rules. There was 3 points I had to consider, according to previous discussion.
1) Tuning hash function
I tried to tune hash function(AVTAB_HASH) for avtab.
But I found it is better not to change hash function.
I compared 3 hash functions, default, jhash, hash_long. default is default AVTAB_HASH.
jhash is function defined in linux/jhash.h.hash_long is defined in linux/hash.h, I used it like following.
(int)(hash_long(((unsigned long)keyp->target_class)+
(((unsigned long)keyp->target_type)<<2)+
(((unsigned long)keyp->source_type)<<9) , bits))According to benchmark result in 3.2(1)(2),
chain length of jhash/hash_long are better.
However, performance is worse.
So, I think it is better not to change hash function for avtab.
2) Number of dynamically allocated hash slots I decided to allocate <number of rules>/4 hash slots. Because performance remains almost the same, see benchmark result in 3.2(2).
3) Max number of hash slots
There is max number of hash slots.
It was 32768 in previous patch.
I found we can reduce it to 8192.
Performance had not got worse, see benchmark result in 3.1(1). I also replaced vmalloc with kmalloc to allocate hash slots.
2. Memory usage
I measured memory usage by /proc/memstat before/after tuning.
* Memory usage: SELinux before loading policy.
2720k is used.
* Memory usage: SELinux after loading policy(about 8000 rules) before patch +1116k increase
* Memory usage: SELinux after loading poilcy(about 8000 rules) after patch. configured AVTAB_HASH_BITS as "13"
+780k increase
-> improved 336k
3. Benchmark
3.1 Explanation of benchmark
To measure performance,
I measured time to call security_compute_av varying number of hash slots and hash functions.
I measured time 10000 security_compute_av call from system boot, using below code.
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested, struct av_decision *avd)
{
struct avc_node *node;
struct avc_entry entry, *p_ae;
int rc = 0;
u32 denied;+ unsigned long long t0,t1;
+ unsigned long long t2=0;
+ static unsigned long long t3=0;
+ static int count = 0;
+ static int flag = 1;
+ static int max = 10000;
+ int i = 0;
rcu_read_lock();
+ if (flag && ss_initialized) {
+ t0 = sched_clock();
+ security_compute_av(ssid,tsid,tclass, requested, &entry.avd);
+ t1 = sched_clock();
+ t2 = t1 - t0;
+ t3 += t2;
+ count ++;
+ }
+ if (flag && (count == max)) {
+ flag = 0;
+ printk("SELinux:security_compute_av execution time:%Lu\n", t3);
+
+ }
security_compute_av is located at the entry of avc_has_perm_no_audit. And nano second to call 10000 security_compute_av function is printed out.
3.2 Benchmark Result
1) Benchmark for full strict policy, x86 system
This benchmark is to see performance for PC system with full SELinux feature. ** Environment
* Policy: selinux-policy-strict-2.4.6-80.fc6
166741 unconditional rules
* Kernel: linux-2.6.22
* CPU: Pentium 4 2.26 GHz
* RAM: 1GB
In this environment, max number of hash slot is allocated.
** Result
* number of hash slots: 32768
longest chain length time to call security compute_av Default hash 34 0.87(s) jhash 21 1.10(s) hash_long 17 0.99(s)
* hash slot: 8192
longest chain length time to call security compute_av Default hash 97 1.00(s) jhash 41 1.92(s) hash_long 43 1.42(s)
* hash slot: 4096
longest chain length time to call security compute_av Default hash 182 1.14(s) jhash 41 3.33(s) hash_long 43 2.19(s)
2) Benchmark for small policy, embedded system This benchmark is to see performance for small system. I made small refpolicy, and run on embedded CPU.
** Environment
* Policy: serefpolicy-2.4.6, build with targeted 8188 unconditional rules
* Kernel: linux-2.6.22
* CPU: SH-4(SH 7751R) 240Mhz
* RAM: 64M
** Result
* Number of slot(8192) = num of rules
longest chain length time to call security compute_av
Default hash 13 9.67(s) hash_long 8 9.78(s)
* Number of slot(4096) = num of rules/2
longest chain length time to call security compute_av
Default hash 21 9.65(s) hash_long 10 9.85(s)
* Number of slot(2048) = num of rules/4
longest chain length time to call security compute_av Default hash 35 9.68(s) hash_long 13 9.99(s)
* Number of slot(1024) = num of rules/8
longest chain length time to call security compute_av Default hash 64 9.78(s) hash_long 19 10.25(s)
Next is a patch.
----
avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------------- avtab.h | 13 +++++++----- conditional.c | 6 +++++ policydb.c | 9 ++------ 4 files changed, 64 insertions(+), 25 deletions(-)
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +47 -14
@@ -16,17 +16,16 @@#include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> #include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ +#define AVTAB_HASH (keyp,mask) \ ((keyp->target_class + \ (keyp->target_type << 2) + \ (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) + mask)static struct kmem_cache *avtab_node_cachep;
@@ -62,7 +61,7 @@if (!h)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key,h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -102,7 +101,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -135,7 +134,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -170,7 +169,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -228,7 +227,7 @@if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;
@@ -237,21 +236,48 @@ } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} + +int avtab_alloc (struct avtab *h,int nrules) {int i; +u16 mask; +u32 shift =0 ; +u32 work = nrules; +u32 nslot; + +while (work) { + work = work>>1 ; + shift++; + } +if (shift >2 ) { + shift = shift -2 ; + } + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) { + nslot =MAX_AVTAB_SIZE ; + } + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kmalloc (sizeof (*(h->htable)) * nslot,GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) +for (i =0 ; i < nslot; i++) h->htable[i] =NULL ; h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n" , h->nslot, nrules);return 0 ; }
@@ -262,7 +288,7 @@ slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;
@@ -278,7 +304,7 @@ }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , +"chain length %d\n" , tag, h->nel, slots_used, h->nslot, max_chain_len); }
@@ -419,6 +445,13 @@ rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) { + rc = -ENOMEM ; + goto bad; + } +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {
selinux/ss/avtab.h renamed from selinux.notuning/ss/avtab.h +8 -5
@@ -50,9 +50,13 @@struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,int );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);
@@ -74,11 +78,10 @@void avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */
selinux/ss/conditional.c renamed from selinux.notuning/ss/conditional.c +6 -0
@@ -455,6 +455,12 @@return -1 ; len =le32_to_cpu (buf[0 ]); + + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) { + rc = -ENOMEM ; + goto err; + }for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );
selinux/ss/policydb.c renamed from selinux.notuning/ss/policydb.c +3 -6
@@ -172,22 +172,19 @@ rc =avtab_init (&p->te_avtab);if (rc) - goto out_free_symtab; + goto out_free_symtab; rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 178 lines · Yuichi Nakamura
Hi.
I would like to propose patch that reduce memory usage of avtab again. It reduces number of hash slots of avtab.
Previous patch was discussed in past threads.
http://marc.info/?t=118517459600001&r=1&w=2
http://marc.info/?t=118526972800008&r=1&w=2
http://marc.info/?t=118647810000001&r=1&w=20. Background
* Inavtab_init:
h->htable=vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
Number of hash table size isAVTAB_SIZE.* In
avtab.h
#defineAVTAB_HASH_BITS15
#defineAVTAB_HASH_BUCKETS(1 <<AVTAB_HASH_BITS)
#defineAVTAB_SIZEAVTAB_HASH_BUCKETS
AVTAB_SIZEis 2^15 = 32768So 32768 entries are allocated for avtab,
and 2 avtabs are used in policydb:
struct avtabte_avtab;
struct avtabte_cond_avtab;If te rules are fewer than 32768,
unused entries are using memory.In embedded devices, the rules tend to be fewer.
In my test system(SH architecture board), it is less than 10000 rules. We want to save memory for embedded devices.1. Explanation of patch
It decides number of hash slots dynamically based on number of rules. There was 3 points I had to consider, according to previous discussion.
1) Tuning hash function
I tried to tune hashfunction(AVTAB_HASH)for avtab.
But I found it is better not to change hash function.I compared 3 hash functions, default, jhash,
hash_long. default is defaultAVTAB_HASH.
jhash is function defined inlinux/jhash.h.hash_longis defined inlinux/hash.h, I used it like following.(int)(hash_long(((unsigned long)keyp->target_class)+ (((unsigned long)keyp->target_type)<<2)+ (((unsigned long)keyp->source_type)<<9) , bits))According to benchmark result in 3.2(1)(2),
chain length of jhash/hash_long are better.
However, performance is worse.
So, I think it is better not to change hash function for avtab.2) Number of dynamically allocated hash slots I decided to allocate <number of rules>/4 hash slots. Because performance remains almost the same, see benchmark result in 3.2(2).
3) Max number of hash slots
There is max number of hash slots.
It was 32768 in previous patch.
I found we can reduce it to 8192.
Performance had not got worse, see benchmark result in 3.1(1). I also replaced vmalloc with kmalloc to allocate hash slots.2. Memory usage
I measured memory usage by/proc/memstatbefore/after tuning.* Memory usage: SELinux before loading policy.
2720k is used.* Memory usage: SELinux after loading policy(about 8000 rules) before patch +1116k increase
* Memory usage: SELinux after loading poilcy(about 8000 rules) after patch. configured
AVTAB_HASH_BITSas "13"
+780k increase
-> improved 336k3. Benchmark
3.1 Explanation of benchmark
To measure performance,
I measured time to callsecurity_compute_avvarying number of hash slots and hash functions.
I measured time 10000security_compute_avcall from system boot, using below code.int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested, structav_decision*avd){ struct avc_node *node; struct avc_entry entry, *p_ae; int rc = 0; u32 denied;(quoted diff) +7
-0+ unsigned long long t0,t1; + unsigned long long t2=0; + static unsigned long long t3=0; + static int count = 0; + static int flag = 1; + static int max = 10000; + int i = 0;rcu_read_lock();(quoted diff) +13
-0+ if (flag && ss_initialized) { + t0 = sched_clock(); + security_compute_av(ssid,tsid,tclass, requested, &entry.avd); + t1 = sched_clock(); + t2 = t1 - t0; + t3 += t2; + count ++; + } + if (flag && (count == max)) { + flag = 0; + printk("SELinux:security_compute_av execution time:%Lu\n", t3); + + }
security_compute_avis located at the entry ofavc_has_perm_no_audit. And nano second to call 10000security_compute_avfunction is printed out.3.2 Benchmark Result
1) Benchmark for full strict policy, x86 system
This benchmark is to see performance for PC system with full SELinux feature. ** Environment
* Policy: selinux-policy-strict-2.4.6-80.fc6
166741 unconditional rules
* Kernel: linux-2.6.22
* CPU: Pentium 4 2.26 GHz
* RAM: 1GB
In this environment, max number of hash slot is allocated.** Result
* number of hash slots: 32768longest chain length time to call security compute_av Default hash 34 0.87(s) jhash 21 1.10(s) hash_long 17 0.99(s)* hash slot: 8192
longest chain length time to call security compute_av Default hash 97 1.00(s) jhash 41 1.92(s) hash_long 43 1.42(s)* hash slot: 4096
longest chain length time to call security compute_av Default hash 182 1.14(s) jhash 41 3.33(s) hash_long 43 2.19(s)2) Benchmark for small policy, embedded system This benchmark is to see performance for small system. I made small refpolicy, and run on embedded CPU.
** Environment
* Policy: serefpolicy-2.4.6, build with targeted 8188 unconditional rules
* Kernel: linux-2.6.22
* CPU: SH-4(SH 7751R) 240Mhz
* RAM: 64M** Result
* Number of slot(8192) = num of rules
longest chain length time to call securitycompute_avDefault hash 13 9.67(s) hash_long 8 9.78(s)* Number of slot(4096) = num of rules/2
longest chain length time to call securitycompute_avDefault hash 21 9.65(s) hash_long 10 9.85(s)* Number of slot(2048) = num of rules/4
Quoted 8 lines
longest chain length time to call security compute_av Default hash 35 9.68(s) hash_long 13 9.99(s)* Number of slot(1024) = num of rules/8
longest chain length time to call security compute_av Default hash 64 9.78(s) hash_long 19 10.25(s)
The divergence in times between strict/large policy vs. targeted/small policy seems curious.
Is it because targeted/small policy makes more use of type attributes, making the nested ebitmap_for_each_bit loops much longer?
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (include/linux/bitmap.h, lib/bitmap.c). For example, ebitmap_next could possibly use find_next_bit().
Quoted 3 lines
Next is a patch.
Signed-off-by Yuichi Nakamura <[email protected]>
Looks ok, but a few coding style issues. Run ./scripts/checkpatch.pl on it and fix all issues please. And make it apply with patch -p1 (and use diffstat -p1 to generate the diffstat).
Quoted 241 lines
----
avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------------- avtab.h | 13 +++++++----- conditional.c | 6 +++++ policydb.c | 9 ++------ 4 files changed, 64 insertions(+), 25 deletions(-)diff -ur
security/selinux.notuning/ss/avtab.csecurity/selinux/ss/avtab.cselinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +47
-14@@ -16,17 +16,16 @@#include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> #include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ +#define AVTAB_HASH (keyp,mask) \ ((keyp->target_class + \ (keyp->target_type << 2) + \ (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) + mask)static struct kmem_cache *avtab_node_cachep;@@ -62,7 +61,7 @@if (!h)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key,h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {@@ -102,7 +101,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {@@ -135,7 +134,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -170,7 +169,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -228,7 +227,7 @@if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;@@ -237,21 +236,48 @@ } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} + +int avtab_alloc (struct avtab *h,int nrules) {int i; +u16 mask; +u32 shift =0 ; +u32 work = nrules; +u32 nslot; + +while (work) { + work = work>>1 ; + shift++; + } +if (shift >2 ) { + shift = shift -2 ; + } + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) { + nslot =MAX_AVTAB_SIZE ; + } + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kmalloc (sizeof (*(h->htable)) * nslot,GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) +for (i =0 ; i < nslot; i++) h->htable[i] =NULL ; h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n" , h->nslot, nrules);return 0 ; }@@ -262,7 +288,7 @@ slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;@@ -278,7 +304,7 @@ }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , +"chain length %d\n" , tag, h->nel, slots_used, h->nslot, max_chain_len); }@@ -419,6 +445,13 @@ rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) { + rc = -ENOMEM ; + goto bad; + } +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {diff -ur
security/selinux.notuning/ss/avtab.hsecurity/selinux/ss/avtab.hselinux/ss/avtab.h renamed from selinux.notuning/ss/avtab.h +8
-5@@ -50,9 +50,13 @@struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,int );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);@@ -74,11 +78,10 @@void avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */ diff -ur
security/selinux.notuning/ss/conditional.csecurity/selinux/ss/conditional.cselinux/ss/conditional.c renamed from selinux.notuning/ss/conditional.c +6
-0@@ -455,6 +455,12 @@return -1 ; len =le32_to_cpu (buf[0 ]); + + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) { + rc = -ENOMEM ; + goto err; + }for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );diff -ur
security/selinux.notuning/ss/policydb.csecurity/selinux/ss/policydb.cselinux/ss/policydb.c renamed from selinux.notuning/ss/policydb.c +3
-6@@ -172,22 +172,19 @@ rc =avtab_init (&p->te_avtab);if (rc) - goto out_free_symtab; + goto out_free_symtab; rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);Regards,
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 1 line · On Tue, 21 Aug 2007 09:47:38 -0400 Stephen Smalley wrote:
On Tue, 2007-08-21 at 13:29 +0900, Yuichi Nakamura wrote:
<snip>
Quoted 6 lines
The divergence in times between strict/large policy vs. targeted/small policy seems curious.
Is it because targeted/small policy makes more use of type attributes, making the nested
ebitmap_for_each_bitloops much longer?
I think so.
Targeted policy uses more attributes.
For example,
Number of attribute for kernel_t, init_t, initrc_t is:
strict policy -> 8, 8, 16
small refpolicy(build as targeted)-> 24,24,32
Quoted 3 lines
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (
include/linux/bitmap.h,lib/bitmap.c). For example,ebitmap_nextcould possibly usefind_next_bit().
I want to look after this patch is done..
Quoted 8 lines
Quoted 4 lines
Next is a patch.
Signed-off-by Yuichi Nakamura <[email protected]>Looks ok, but a few coding style issues. Run
./scripts/checkpatch.plon it and fix all issues please. And make it apply with patch -p1 (and use diffstat -p1 to generate the diffstat).
Thanks, about them I will work tomorrow :)
Quoted 240 lines
Quoted 240 lines
Quoted 1 line
----
avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------------- avtab.h | 13 +++++++----- conditional.c | 6 +++++ policydb.c | 9 ++------ 4 files changed, 64 insertions(+), 25 deletions(-)diff -ur
security/selinux.notuning/ss/avtab.csecurity/selinux/ss/avtab.cselinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +47
-14@@ -16,17 +16,16 @@#include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> #include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ +#define AVTAB_HASH (keyp,mask) \ ((keyp->target_class + \ (keyp->target_type << 2) + \ (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) + mask)static struct kmem_cache *avtab_node_cachep;@@ -62,7 +61,7 @@if (!h)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key,h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {@@ -102,7 +101,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {@@ -135,7 +134,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -170,7 +169,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -228,7 +227,7 @@if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;@@ -237,21 +236,48 @@ } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} + +int avtab_alloc (struct avtab *h,int nrules) {int i; +u16 mask; +u32 shift =0 ; +u32 work = nrules; +u32 nslot; + +while (work) { + work = work>>1 ; + shift++; + } +if (shift >2 ) { + shift = shift -2 ; + } + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) { + nslot =MAX_AVTAB_SIZE ; + } + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kmalloc (sizeof (*(h->htable)) * nslot,GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) +for (i =0 ; i < nslot; i++) h->htable[i] =NULL ; h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n" , h->nslot, nrules);return 0 ; }@@ -262,7 +288,7 @@ slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;@@ -278,7 +304,7 @@ }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , +"chain length %d\n" , tag, h->nel, slots_used, h->nslot, max_chain_len); }@@ -419,6 +445,13 @@ rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) { + rc = -ENOMEM ; + goto bad; + } +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {diff -ur
security/selinux.notuning/ss/avtab.hsecurity/selinux/ss/avtab.hselinux/ss/avtab.h renamed from selinux.notuning/ss/avtab.h +8
-5@@ -50,9 +50,13 @@struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,int );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);@@ -74,11 +78,10 @@void avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */ diff -ur
security/selinux.notuning/ss/conditional.csecurity/selinux/ss/conditional.cselinux/ss/conditional.c renamed from selinux.notuning/ss/conditional.c +6
-0@@ -455,6 +455,12 @@return -1 ; len =le32_to_cpu (buf[0 ]); + + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) { + rc = -ENOMEM ; + goto err; + }for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );diff -ur
security/selinux.notuning/ss/policydb.csecurity/selinux/ss/policydb.cselinux/ss/policydb.c renamed from selinux.notuning/ss/policydb.c +3
-6@@ -172,22 +172,19 @@ rc =avtab_init (&p->te_avtab);if (rc) - goto out_free_symtab; + goto out_free_symtab; rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);
Quoted 10 lines
Quoted 1 line
Regards,
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 3 lines · Stephen Smalley
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (
include/linux/bitmap.h,lib/bitmap.c). For example,ebitmap_nextcould possibly usefind_next_bit().
[Removed the busybox list because I'm sure they don't care]
Would the fact that the MLS category bitmaps grow to 1024 bits be a concern with using a single contiguous bitmap instead of the sparse bitmap the ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel bitmap would most certainly be better but I wonder what the common case is (and if the MLS compartments even factor into the discussion) and which type is better suited to handle this case.
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 5 lines · Paul Moore
Quoted 3 lines · Stephen Smalley
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (
include/linux/bitmap.h,lib/bitmap.c). For example,ebitmap_nextcould possibly usefind_next_bit().
Quoted 8 lines
[Removed the busybox list because I'm sure they don't care]
Would the fact that the MLS category bitmaps grow to 1024 bits be a concern with using a single contiguous bitmap instead of the sparse bitmap the ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel bitmap would most certainly be better but I wonder what the common case is (and if the MLS compartments even factor into the discussion) and which type is better suited to handle this case.
Even if we retain the ebitmap type as a sparse bitmap, I think we can do some optimization of its internals, possibly leveraging things like find_next_bit(), to speed up the loops that were introduced when we optimized the avtab memory layout by pushing attributes down into the kernel policy (policy.20).
Trying Yuichi's simple instrumentation of security_compute_av, I see a huge difference in security_compute_av times between policy.19 and policy.20. We knew it would slow security_compute_av down (standard tradeoff between runtime performance and memory use), but the thinking at the time was that it wouldn't matter because of the AVC. But we do have to bound our worst case latency.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 21 lines · Stephen Smalley
Quoted 5 lines · Paul Moore
Quoted 3 lines · Stephen Smalley
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (
include/linux/bitmap.h,lib/bitmap.c). For example,ebitmap_nextcould possibly usefind_next_bit().Quoted 8 lines
[Removed the busybox list because I'm sure they don't care]
Would the fact that the MLS category bitmaps grow to 1024 bits be a concern with using a single contiguous bitmap instead of the sparse bitmap the ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel bitmap would most certainly be better but I wonder what the common case is (and if the MLS compartments even factor into the discussion) and which type is better suited to handle this case.
Even if we retain the ebitmap type as a sparse bitmap, I think we can do some optimization of its internals, possibly leveraging things like
find_next_bit(), to speed up the loops that were introduced when we optimized the avtab memory layout by pushing attributes down into the kernel policy (policy.20).
Quoted 6 lines
Trying Yuichi's simple instrumentation of
security_compute_av, I see a huge difference insecurity_compute_avtimes between policy.19 and policy.20. We knew it would slowsecurity_compute_avdown (standard tradeoff between runtime performance and memory use), but the thinking at the time was that it wouldn't matter because of the AVC. But we do have to bound our worst case latency.
I understand, I was just slightly concerned about losing the sparse bitmap feature which I have a hunch is beneficial in the MLS compartment case. Although I will readily admit I have no data to support this claim, I just wanted to throw it out as something to consider.
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 20 lines · Paul Moore
Quoted 19 lines · Stephen Smalley
Quoted 4 lines · Paul Moore
Quoted 3 lines · Stephen Smalley
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (
include/linux/bitmap.h,lib/bitmap.c). For example,ebitmap_nextcould possibly usefind_next_bit().Quoted 8 lines
[Removed the busybox list because I'm sure they don't care]
Would the fact that the MLS category bitmaps grow to 1024 bits be a concern with using a single contiguous bitmap instead of the sparse bitmap the ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel bitmap would most certainly be better but I wonder what the common case is (and if the MLS compartments even factor into the discussion) and which type is better suited to handle this case.
Even if we retain the ebitmap type as a sparse bitmap, I think we can do some optimization of its internals, possibly leveraging things like
find_next_bit(), to speed up the loops that were introduced when we optimized the avtab memory layout by pushing attributes down into the kernel policy (policy.20).
Quoted 8 lines
Quoted 6 lines
Trying Yuichi's simple instrumentation of
security_compute_av, I see a huge difference insecurity_compute_avtimes between policy.19 and policy.20. We knew it would slowsecurity_compute_avdown (standard tradeoff between runtime performance and memory use), but the thinking at the time was that it wouldn't matter because of the AVC. But we do have to bound our worst case latency.I understand, I was just slightly concerned about losing the sparse bitmap feature which I have a hunch is beneficial in the MLS compartment case. Although I will readily admit I have no data to support this claim, I just wanted to throw it out as something to consider.
I think the sparse bitmap feature is also useful to skip unnecessary scan on the ebitmap, so these features should be used together.
The current version of ebitmap contains a 64-bit length bitmap. I have a concern to apply the standard bitops, and memory usage.
The one is a difference in the type of variable. find_next_bit() requires the bitmap defined as unsigned long array, but ebitmap uses a u64 value as a bitmap, so we cannot apply it as is.
The other is memory usage. The ebitmap_node is allocated by kzalloc(). However, sizeof(ebitmap_node) is 16-byte in 32bit arch, although the minimun unit of kmalloc() is 32 byte.
In 32-bit arch, map should be defined as 'unsigned long map[6]' to apply the standard bitops and to maximun memory usage.
Thanks,
Signature · 7 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
Real-time responsibility is a significant issue for embedded Linux people. This patch also reduce amount of busy loop in the kernel, so it can improve real-time responsibility.
I added ebitmap_for_each_positive_bit() macro not to walk on any native bit within ebitmap, and applies it on
- context_struct_compute_av()
- security_get_user_sids()
- mls_context_isvalid()
ebitmap_node was redefined as follows:
#define EBITMAP_UNIT_NUMS \
((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
struct ebitmap_node {
struct ebitmap_node *next;
unsigned long maps[EBITMAP_UNIT_NUMS];
u32 startbit;};
"u64 map" is replaced by an array of "unsigned long". It enables to apply standard bit operations. In addition, length of the array is determind to fit 32-bytes, the minimum size of kmalloc().
The result of benchmarks seems to me fine.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]
NOTE: We used the following operatins as a test case.
No need to say, it is a corner case to highlight.
[root@saba ~]# id -Z root:system_r:unconfined_t:SystemLow-SystemHigh [root@saba ~]# cd /dev/shm
[root@saba shm]# for I in seq 1 640
Quoted 4 lines
do
echo > file${I} chcon -l s0:c${I} file${I}done
[root@saba shm]# ~kaigai/manyfiles 800 file*
I also attached "manyfiles.c" to reproduce them.
In addition, we could not make sure a statistical difference in the AVC-hits case.
Thanks,
Quoted 48 lines · KaiGai Kohei
Quoted 20 lines · Paul Moore
Quoted 19 lines · Stephen Smalley
Quoted 4 lines · Paul Moore
Quoted 3 lines · Stephen Smalley
We likely should look at optimizing the ebitmap code, or replacing it with the native kernel bitmaps (
include/linux/bitmap.h,lib/bitmap.c). For example,ebitmap_nextcould possibly usefind_next_bit().Quoted 8 lines
[Removed the busybox list because I'm sure they don't care]
Would the fact that the MLS category bitmaps grow to 1024 bits be a concern with using a single contiguous bitmap instead of the sparse bitmap the ebitmap currently uses? Granted, in the worst case of c0.c1023 the kernel bitmap would most certainly be better but I wonder what the common case is (and if the MLS compartments even factor into the discussion) and which type is better suited to handle this case.
Even if we retain the ebitmap type as a sparse bitmap, I think we can do some optimization of its internals, possibly leveraging things like
find_next_bit(), to speed up the loops that were introduced when we optimized the avtab memory layout by pushing attributes down into the kernel policy (policy.20).Quoted 8 lines
Quoted 6 lines
Trying Yuichi's simple instrumentation of
security_compute_av, I see a huge difference insecurity_compute_avtimes between policy.19 and policy.20. We knew it would slowsecurity_compute_avdown (standard tradeoff between runtime performance and memory use), but the thinking at the time was that it wouldn't matter because of the AVC. But we do have to bound our worst case latency.I understand, I was just slightly concerned about losing the sparse bitmap feature which I have a hunch is beneficial in the MLS compartment case. Although I will readily admit I have no data to support this claim, I just wanted to throw it out as something to consider.
I think the sparse bitmap feature is also useful to skip unnecessary scan on the ebitmap, so these features should be used together.
The current version of ebitmap contains a 64-bit length bitmap. I have a concern to apply the standard bitops, and memory usage.
The one is a difference in the type of variable.
find_next_bit()requires the bitmap defined as unsigned long array, but ebitmap uses a u64 value as a bitmap, so we cannot apply it as is.The other is memory usage. The
ebitmap_nodeis allocated bykzalloc(). However,sizeof(ebitmap_node)is 16-byte in 32bit arch, although the minimun unit ofkmalloc()is 32 byte.In 32-bit arch, map should be defined as 'unsigned long map[6]' to apply the standard bitops and to maximun memory usage.
Thanks,
Signature · 2 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]>
security/selinux/ss/ebitmap.c +125 -113
@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;
@@ -84,7 +88,8 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i;/* This function is a much simpler because SELinux's MAPTYPE happens * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
@@ -104,19 +109,20 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i=0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; +if (e_startbit >= c_iter->startbit +NETLBL_CATMAP_SIZE ) { + c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + cmap_idx = (e_startbit - c_iter->startbit) /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = (e_startbit - c_iter->startbit) %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;
@@ -128,7 +134,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description:
@@ -142,7 +148,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft;/* This function is a much simpler because SELinux's MAPTYPE happens * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
@@ -152,26 +158,34 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + e_idx = (c_pos - e_iter->startbit) /EBITMAP_UNIT_SIZE ; + e_sft = (c_pos - e_iter->startbit) %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);
@@ -186,6 +200,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;
@@ -197,8 +212,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i=0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;
@@ -219,12 +236,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }
@@ -238,31 +251,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +ebitmap_node_clr_bit (n, bit); + +if (find_first_bit (n->maps,EBITMAP_SIZE ) <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }
@@ -277,12 +290,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;
@@ -316,11 +329,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);
@@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); + +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; }if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *_n =kzalloc (sizeof (*_n),GFP_KERNEL ); +if (!_n) { +printk (KERN_ERR "security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } + _n->startbit = startbit - (startbit %EBITMAP_SIZE );/* round down */ +if (n) { + n->next = _n; + }else { + e->node = _n; + } + n = _n; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;
security/selinux/ss/ebitmap.h +71 -9
114 lines not on this page · raw message
security/selinux/ss/mls.c +22 -23
57 lines not on this page · raw message
security/selinux/ss/services.c +12 -12
@@ -329,12 +329,12 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +// BUG_ON(!ebitmap_node_get_bit(snode, i)); + +ebitmap_for_each_positive_bit (tattr, tnode, j) { +// BUG_ON(!ebitmap_node_get_bit(tnode, j)); + avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1622,14 +1622,14 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { +// BUG_ON(!ebitmap_node_get_bit(rnode, i)); + role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { +// BUG_ON(!ebitmap_node_get_bit(tnode, j)); + usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon))
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void usage(int exitcode) {
fprintf(stderr, "usage: manyfiles <# of loop> <files ...>\n");
exit(exitcode);
}#define TEST_STR "abcdefghijklmnopqrstuvwxyz0123456789\n"
int main(int argc, char *argv[]) {
char buffer[128];
int i, j, nloops, nfiles, *fd;
struct timeval t1, t2;
double delta;
if (argc < 3)
usage(1);
nloops = atoi(argv[1]);
if (nloops < 1)
nloops = 1;
fd = malloc(sizeof(int *) * argc);
if (!fd) {
fprintf(stderr, "could not allocate memory (%s)\n", strerror(errno));
return 1;
}
for (i=2, nfiles=0; argv[i]; i++) {
fd[nfiles] = open(argv[i], O_RDWR | O_CREAT, 0644);
if (fd[nfiles] < 0) {
fprintf(stderr, "could not open %s (%s)\n",
argv[i], strerror(errno));
continue;
}
nfiles++;
}
gettimeofday(&t1, NULL);
for (i=0; i < nloops; i++) {
for (j=0; j < nfiles; j++) {
lseek(fd[j], 0, SEEK_SET);
write(fd[j], TEST_STR, sizeof(TEST_STR));
}
for (j=0; j < nfiles; j++) {
lseek(fd[j], 0, SEEK_SET);
read(fd[j], buffer, sizeof(buffer));
}
}
gettimeofday(&t2, NULL);
delta = (((double)t2.tv_sec * 1000000.0 + (double)t2.tv_usec)
- ((double)t1.tv_sec * 1000000.0 + (double)t1.tv_usec)) / 1000000.0;
printf("%d files, %d loops, %.3f [sec]\n", nfiles, nloops, delta);
return 0;
}Quoted 3 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
In addition to the code changes to ebitmap_netlbl_{import,export}() you should probably either remove, or preferably update, the comment block in the body of the functions.
Thank you for also fixing my cut and paste error in the comment block at the top of the ebitmap_netlbl_import() function :)
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
PATCH 1/1 Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage)
Quoted 6 lines · Paul Moore
Quoted 3 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
In addition to the code changes to ebitmap_netlbl_{import,export}() you should probably either remove, or preferably update, the comment block in the body of the functions.
I replaced the comment block as follows:
/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
* however, it is not always compatible with an array of unsigned long
* in ebitmap_node.
* In addition, you should pay attention the following implementation
* assumes unsigned long has a width equal with or less than 64-bit. */
BTW, is there any wrapper to copy an array of u64 to/from architecture specific unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}() and ebitmap_read() more simply.
Signature · 7 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage)
Quoted 19 lines · KaiGai Kohei
Quoted 8 lines · Paul Moore
Quoted 3 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
In addition to the code changes to ebitmap_netlbl_{import,export}() you should probably either remove, or preferably update, the comment block in the body of the functions.
I replaced the comment block as follows:
/* NetLabel's
NETLBL_CATMAP_MAPTYPEis defined as an array of u64,
* however, it is not always compatible with an array of unsigned long
* inebitmap_node.
* In addition, you should pay attention the following implementation
* assumes unsigned long has a width equal with or less than 64-bit. */
Quoted 3 lines
BTW, is there any wrapper to copy an array of u64 to/from architecture specific unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}() and
ebitmap_read()more simply.
Might want to ask on linux-kernel. More generally, it might be a good idea to cc linux-kernel on your next posting of the patch to get wider review of how you are using the native linux bitmap support.
The patch looks very promising, although a detailed review and testing might take a little bit.
Signature · 4 lines
-- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Wrappers to load bitmaps (Re: [PATCH] Improve ebitmap scanning)
Now I'm improving the performance to scan bitmap in SELinux, with replacing its original bitmap implementation (ebitmap) by common bitops like find_next_bit().
I posted a patch to replace them, however, it got a bit complex bacause we had to translate u64 <--> unsigned long by myself to adjust between the format of security policy and common bitops.
http://marc.info/?l=selinux&m=118956715414494&w=2
I have an idea to provide several wrapper functions to copy u64/u32 to/from unsigned long for each architecture.
Maybe, it will be defined as follows:
int arraycpy_u64_to_ulong(u64 *src, unsigned long *dest, size_t len); int arraycpy_ulong_to_u64(unsigned long *src, u64 *dest, size_t len);
I believe this feature will help getting code simpler and reducing bugs for any other subsystem, not only SELinux, which loads bitmaps from/to userspace and handle them using common bitops.
Any comment please.
Quoted 6 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei
Quoted 4 lines · Paul Moore
Quoted 3 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
<...snip...>
Quoted 10 lines
Quoted 3 lines
BTW, is there any wrapper to copy an array of u64 to/from architecture specific unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}() and
ebitmap_read()more simply.Might want to ask on linux-kernel. More generally, it might be a good idea to cc linux-kernel on your next posting of the patch to get wider review of how you are using the native linux bitmap support.
The patch looks very promising, although a detailed review and testing might take a little bit.
Signature · 7 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve ebitmap scanning (Re: [patch] Tuning avtab to reduce memory usage)
In reply to KaiGai KoheiQuoted 10 lines · KaiGai Kohei
Quoted 8 lines · Paul Moore
Quoted 3 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
In addition to the code changes to ebitmap_netlbl_{import,export}() you should probably either remove, or preferably update, the comment block in the body of the functions.
Quoted 8 lines
I replaced the comment block as follows:
/* NetLabel's
NETLBL_CATMAP_MAPTYPEis defined as an array of u64,
* however, it is not always compatible with an array of unsigned long
* inebitmap_node.
* In addition, you should pay attention the following implementation
* assumes unsigned long has a width equal with or less than 64-bit. */
That sound good to me. FWIW, if/when this patch is accepted I'll take a look at the NetLabel security attributes struct as it _may_ be possible to change the NETLBL_CATMAP_MAPTYPE to an unsigned long from the u64 it currently uses. That should make these import/export functions a little cleaner.
Quoted 3 lines
BTW, is there any wrapper to copy an array of u64 to/from architecture specific unsigned long? If so, it will help implement ebitmap_netlbl_{import|export}() and
ebitmap_read()more simply.
I'm not sure, but Stephen's suggestion to ask lkml sounds like a good one.
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 52 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
Real-time responsibility is a significant issue for embedded Linux people. This patch also reduce amount of busy loop in the kernel, so it can improve real-time responsibility.
I added
ebitmap_for_each_positive_bit()macro not to walk on any native bit within ebitmap, and applies it on
-context_struct_compute_av()
-security_get_user_sids()
-mls_context_isvalid()
ebitmap_nodewas redefined as follows:#define EBITMAP_UNIT_NUMS \ ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long)) struct ebitmap_node { struct ebitmap_node *next; unsigned long maps[EBITMAP_UNIT_NUMS]; u32 startbit; };"u64 map" is replaced by an array of "unsigned long". It enables to apply standard bit operations. In addition, length of the array is determind to fit 32-bytes, the minimum size of
kmalloc().The result of benchmarks seems to me fine.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]NOTE: We used the following operatins as a test case.
No need to say, it is a corner case to highlight.
[root@saba ~]# id -Z root:system_r:unconfined_t:SystemLow-SystemHigh [root@saba ~]# cd/dev/shm
[root@saba shm]# for I inseq 1 640Quoted 4 lines
do
echo > file${I} chcon -l s0:c${I} file${I}done
Quoted 8 lines
[root@saba shm]# ~kaigai/manyfiles 800 file*
I also attached "
manyfiles.c" to reproduce them.In addition, we could not make sure a statistical difference in the AVC-hits case.
Thanks,
The patch looks good overall - a couple minor comments below. Paul, can you test the netlabel import/export functionality?
I was wondering whether it might be useful to also introduce a new policy version with an updated ebitmap representation in the policy format that would be closer to the kernel native representation, although we'd still need to be able to read the old formats for backward compatibility.
If/when we introduce support for reading back the currently loaded policy image from the kernel via a selinuxfs node for use by tools, we'll need conversion code to map the kernel representation back to the policy format. libsepol has an ebitmap_write() function to generate a linear policy format representation from an in-memory policydb, which could be ported to the kernel (it used to be there too, actually, but was expunged because we didn't need it in the kernel code at the time), but naturally it only deals with the current representation.
security/selinux/ss/ebitmap.c +8 -4
@@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); + +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit);
Here you will display the modified highbit value rather than the one that was actually in the policy image. I think you can just move the check before mutating the highbit.
goto bad;
}
if (!e->highbit) {
e->node = NULL;
goto ok;
}
- if (e->highbit & (MAPSIZE - 1)) {
- printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
- "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
- goto bad;
- }
Not sure why you'd drop this sanity check. As before, it would need to happen before mutating the highbit.
<snip>
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
+ printk(KERN_ERR "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
+ if (n) {
+ n->next = _n;
+ } else {
+ e->node = _n;
+ }
+ n = _n;
+ } else if (startbit <= n->startbit) {
+ printk(KERN_ERR "security: ebitmap: start bit %d"
+ " comes after start bit %d\n",
+ startbit, n->startbit);
Need to bail out here with an appropriate rc value.
security/selinux/ss/ebitmap.h +2 -0
@@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,return ebitmap_startbit (e); } +static inline unsigned int ebitmap_start_positive (struct ebitmap *e, +struct ebitmap_node **n)
I suspect we could just make these all "static" (not explicitly inline) and let the compiler do the right thing. That seemed to be the trend upstream and guidance from arjan.
<snip>
static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
unsigned int bit)
{
- if (n->map & (MAPBIT << (bit - n->startbit)))
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
Possibly the computation of (ofs,index) should be a common macro since it is done in several of these functions.
+
+ if (index < EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))
Possibly BUG_ON(index >= EBITMAP_UNIT_NUMS) instead of silently returning 0 in that case?
return 1;
return 0;
}
-#define ebitmap_for_each_bit(e, n, bit) \
- for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \
+static inline void ebitmap_node_set_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS)
Ditto.
+ n->maps[index] |= (EBITMAP_BIT << ofs);
+}
+
+static inline void ebitmap_node_clr_bit(struct ebitmap_node * n,
+ unsigned int bit)
+{
+ unsigned int index = (bit - n->startbit) / EBITMAP_UNIT_SIZE;
+ unsigned int ofs = (bit - n->startbit) % EBITMAP_UNIT_SIZE;
+
+ if (index < EBITMAP_UNIT_NUMS)
+ n->maps[index] &= ~(EBITMAP_BIT << ofs);
+}
+
+#define ebitmap_for_each_bit(e, n, bit) \
+ for (bit = ebitmap_start(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next(&n, bit)) \
Ideally we'd kill off all uses of ebitmap_for_each_bit and use the _positive_ form in all cases, although I see that would require some changes to the mls logic.
+
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for (bit = ebitmap_start_positive(e, &n); \
+ bit < ebitmap_length(e); \
+ bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
security/selinux/ss/mls.c +2 -11
@@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)if (!levdatum)return 0 ; -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (i > p->p_cats.nprim) -return 0 ; -if (!ebitmap_get_bit (&levdatum->level->cat, i)) -/* -* Category may not be associated with -* sensitivity in low level. -*/ -return 0 ; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +// BUG_ON(!ebitmap_node_get_bit(node, i));
Drop these BUG_ON's out, or uncomment them if you want to keep them for now for testing purposes.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 2 lines · Stephen Smalley
The patch looks good overall - a couple minor comments below. Paul, can you test the netlabel import/export functionality?
Yep, I just ran it through some simple tests using a patched kernel and the categories looked okay (i.e. the same at both ends). I also inspected a few packets by hand and the categories on the wire looked correct as well.
[NOTE: wireshark 0.99.6 appears to have my CIPSO patch in it now so you can use that to decode CIPSO options]
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 55 lines · Stephen Smalley
Quoted 54 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
Real-time responsibility is a significant issue for embedded Linux people. This patch also reduce amount of busy loop in the kernel, so it can improve real-time responsibility.
I added
ebitmap_for_each_positive_bit()macro not to walk on any native bit within ebitmap, and applies it on
-context_struct_compute_av()
-security_get_user_sids()
-mls_context_isvalid()
ebitmap_nodewas redefined as follows:#define EBITMAP_UNIT_NUMS \ ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long)) struct ebitmap_node { struct ebitmap_node *next; unsigned long maps[EBITMAP_UNIT_NUMS]; u32 startbit; };"u64 map" is replaced by an array of "unsigned long". It enables to apply standard bit operations. In addition, length of the array is determind to fit 32-bytes, the minimum size of
kmalloc().The result of benchmarks seems to me fine.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]NOTE: We used the following operatins as a test case.
No need to say, it is a corner case to highlight.
[root@saba ~]# id -Z root:system_r:unconfined_t:SystemLow-SystemHigh [root@saba ~]# cd/dev/shm
[root@saba shm]# for I inseq 1 640Quoted 4 lines
do
echo > file${I} chcon -l s0:c${I} file${I}done
[root@saba shm]# ~kaigai/manyfiles 800 file*
Quoted 6 lines
Quoted 6 lines
I also attached "
manyfiles.c" to reproduce them.In addition, we could not make sure a statistical difference in the AVC-hits case.
Thanks,
Stephen, Thanks for your comments.
The attached second patch is revised in several points.
- comment blocks in ebitmap_netlbl_(inport|export) are rewritten as I mentioned before.
- rest of codes using ebitmap_for_each_bit() were replaced by _positive_ version. I had to modify logic in ss/mls.c a bit.
- applied your comment as follows:
Quoted 8 lines
The patch looks good overall - a couple minor comments below. Paul, can you test the netlabel import/export functionality?
I was wondering whether it might be useful to also introduce a new policy version with an updated ebitmap representation in the policy format that would be closer to the kernel native representation, although we'd still need to be able to read the old formats for backward compatibility.
I don't think a new policy format is necessary, because the width of unsigned long depends on its architecture, although selinux-policy is a "noarch" package.
The kernel should translate it into another format easier to handle on run-time, if necessary.
Quoted 34 lines
If/when we introduce support for reading back the currently loaded policy image from the kernel via a selinuxfs node for use by tools, we'll need conversion code to map the kernel representation back to the policy format. libsepol has an
ebitmap_write()function to generate a linear policy format representation from an in-memory policydb, which could be ported to the kernel (it used to be there too, actually, but was expunged because we didn't need it in the kernel code at the time), but naturally it only deals with the current representation.security/selinux/ss/ebitmap.c +8
-4@@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); + +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit);
Quoted 3 lines
Here you will display the modified highbit value rather than the one that was actually in the policy image. I think you can just move the check before mutating the highbit.
I moved it in front of rounding up e->highbit.
Quoted 12 lines
security/selinux/ss/ebitmap.c +0
-5goto bad; }if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - }
Quoted 1 line
Not sure why you'd drop this sanity check. As before, it would need to happen before mutating the highbit.
The reason why I dropped this sanity check is to avoid redundant one, because e->highbit is already rounded up to the align of EBITMAP_SIZE. The above condition is not always false.
Quoted 6 lines
security/selinux/ss/ebitmap.c +4
-0+ }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit);Need to bail out here with an appropriate rc value.
I added "goto bad;" at the point. It returns -EINVAL.
Quoted 12 lines
security/selinux/ss/ebitmap.h +2
-0@@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,return ebitmap_startbit (e); } +static inline unsigned int ebitmap_start_positive(struct ebitmap *e, + struct ebitmap_node **n) I suspect we could just make these all "static" (not explicitly inline)
Quoted 2 lines
and let the compiler do the right thing. That seemed to be the trend upstream and guidance from arjan.
How should we do the explicitly inlined static functions used as stubs?
For example, ebitmap_netlbl_export() when NetLabel is not enabled is defined as explicitly inlined function which always returns -ENOMEM, however, these are also declarations of function when NetLabel is enabled.
Quoted 10 lines
<snip>
static inline int ebitmap_node_get_bit(structebitmap_node* n,security/selinux/ss/ebitmap.h +2
-1unsigned int bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) +unsigned int ofs = (bit - n->startbit) %EBITMAP_UNIT_SIZE ; +unsigned int index = (bit - n->startbit) /EBITMAP_UNIT_SIZE ;Possibly the computation of (ofs,index) should be a common macro since it is done in several of these functions.
I added EBITMAP_NODE_INDEX(node,bit) and EBITMAP_NODE_OFFSET(node,bit) to compute them.
Quoted 4 lines
security/selinux/ss/ebitmap.h +2
-0+ +if (index <EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))Possibly
BUG_ON(index >= EBITMAP_UNIT_NUMS)instead of silently returning 0 in that case?
It is good idea indeed.
All caller of ebitmap_node_get_bit() always confirms 'bit' is in the range of ebitmap_node. If the index overs EBITMAP_UNIT_NUMS, it is a bug surely.
Quoted 7 lines
security/selinux/ss/ebitmap.h +4
-0+#define ebitmap_for_each_bit (e, n, bit) \ + for (bit = ebitmap_start(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next(&n, bit)) \Ideally we'd kill off all uses of
ebitmap_for_each_bitand use the _positive_ form in all cases, although I see that would require some changes to the mls logic.
ebitmap_start, ebitmap_next and ebitmap_for_each_bit are dropped. The rest of codes using ebitmap_for_each_bit(), in ss/mls.c, are also replaced with _positive_ version.
Quoted 29 lines
security/selinux/ss/ebitmap.h +4
-0+#define ebitmap_for_each_positive_bit (e, n, bit) \ + for (bit = ebitmap_start_positive(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next_positive(e, &n, bit)) \int ebitmap_cmp (struct ebitmap *e1,struct ebitmap *e2);int ebitmap_cpy (struct ebitmap *dst,struct ebitmap *src);security/selinux/ss/mls.c +2
-11@@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)if (!levdatum)return 0 ; -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (i > p->p_cats.nprim) -return 0 ; -if (!ebitmap_get_bit (&levdatum->level->cat, i)) -/* -* Category may not be associated with -* sensitivity in low level. -*/ -return 0 ; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +// BUG_ON(!ebitmap_node_get_bit(node, i));
Quoted 1 line
Drop these BUG_ON's out, or uncomment them if you want to keep them for now for testing purposes.
I dropped the BUG_ON() to confirm each bit is actually positive.
Thanks,
Signature · 2 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]>
security/selinux/ss/ebitmap.c +139 -123
@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;
@@ -104,19 +110,20 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i=0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; +if (e_startbit >= c_iter->startbit +NETLBL_CATMAP_SIZE ) { + c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + cmap_idx = (e_startbit - c_iter->startbit) /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = (e_startbit - c_iter->startbit) %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;
@@ -128,7 +135,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description:
@@ -142,36 +149,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + e_idx = (c_pos - e_iter->startbit) /EBITMAP_UNIT_SIZE ; + e_sft = (c_pos - e_iter->startbit) %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);
@@ -186,6 +202,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;
@@ -197,8 +214,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i=0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;
@@ -219,12 +238,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }
@@ -238,31 +253,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +ebitmap_node_clr_bit (n, bit); + +if (find_first_bit (n->maps,EBITMAP_SIZE ) <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }
@@ -277,12 +292,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;
@@ -316,11 +331,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);
@@ -328,85 +343,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *_n =kzalloc (sizeof (*_n),GFP_KERNEL ); +if (!_n) { +printk (KERN_ERR "security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } + _n->startbit = startbit - (startbit %EBITMAP_SIZE );/* round down */ +if (n) { + n->next = _n; + }else { + e->node = _n; + } + n = _n; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;
security/selinux/ss/ebitmap.h +67 -20
120 lines not on this page · raw message
security/selinux/ss/mls.c +56 -78
197 lines not on this page · raw message
security/selinux/ss/services.c +4 -12
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon))
Quoted 171 lines · KaiGai Kohei
Quoted 55 lines · Stephen Smalley
Quoted 54 lines · KaiGai Kohei
The attached patch applies the standard bitmap operations for the iteration macro of ebitmap, and enables to improve the performance in AVC-misses case.
Real-time responsibility is a significant issue for embedded Linux people. This patch also reduce amount of busy loop in the kernel, so it can improve real-time responsibility.
I added
ebitmap_for_each_positive_bit()macro not to walk on any native bit within ebitmap, and applies it on
-context_struct_compute_av()
-security_get_user_sids()
-mls_context_isvalid()
ebitmap_nodewas redefined as follows:#define EBITMAP_UNIT_NUMS \ ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long)) struct ebitmap_node { struct ebitmap_node *next; unsigned long maps[EBITMAP_UNIT_NUMS]; u32 startbit; };"u64 map" is replaced by an array of "unsigned long". It enables to apply standard bit operations. In addition, length of the array is determind to fit 32-bytes, the minimum size of
kmalloc().The result of benchmarks seems to me fine.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]NOTE: We used the following operatins as a test case.
No need to say, it is a corner case to highlight.
[root@saba ~]# id -Z root:system_r:unconfined_t:SystemLow-SystemHigh [root@saba ~]# cd/dev/shm
[root@saba shm]# for I inseq 1 640Quoted 4 lines
do
echo > file${I} chcon -l s0:c${I} file${I}done
[root@saba shm]# ~kaigai/manyfiles 800 file*
Quoted 6 lines
Quoted 6 lines
I also attached "
manyfiles.c" to reproduce them.In addition, we could not make sure a statistical difference in the AVC-hits case.
Thanks,
Stephen, Thanks for your comments.
The attached second patch is revised in several points.
- comment blocks inebitmap_netlbl_(inport|export)are rewritten as I mentioned before.
- rest of codes usingebitmap_for_each_bit()were replaced by _positive_ version. I had to modify logic inss/mls.ca bit.
- applied your comment as follows:Quoted 8 lines
The patch looks good overall - a couple minor comments below. Paul, can you test the netlabel import/export functionality?
I was wondering whether it might be useful to also introduce a new policy version with an updated ebitmap representation in the policy format that would be closer to the kernel native representation, although we'd still need to be able to read the old formats for backward compatibility.
I don't think a new policy format is necessary, because the width of unsigned long depends on its architecture, although selinux-policy is a "noarch" package.
The kernel should translate it into another format easier to handle on run-time, if necessary.Quoted 34 lines
If/when we introduce support for reading back the currently loaded policy image from the kernel via a selinuxfs node for use by tools, we'll need conversion code to map the kernel representation back to the policy format. libsepol has an
ebitmap_write()function to generate a linear policy format representation from an in-memory policydb, which could be ported to the kernel (it used to be there too, actually, but was expunged because we didn't need it in the kernel code at the time), but naturally it only deals with the current representation.security/selinux/ss/ebitmap.c +8
-4@@ -328,85 +341,84 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); + +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit);Quoted 3 lines
Here you will display the modified highbit value rather than the one that was actually in the policy image. I think you can just move the check before mutating the highbit.
I moved it in front of rounding up
e->highbit.Quoted 12 lines
security/selinux/ss/ebitmap.c +0
-5goto bad; }if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - }Quoted 1 line
Not sure why you'd drop this sanity check. As before, it would need to happen before mutating the highbit.
The reason why I dropped this sanity check is to avoid redundant one, because
e->highbitis already rounded up to the align ofEBITMAP_SIZE. The above condition is not always false.Quoted 6 lines
security/selinux/ss/ebitmap.c +4
-0+ }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit);Need to bail out here with an appropriate rc value.
I added "goto bad;" at the point. It returns
-EINVAL.Quoted 12 lines
security/selinux/ss/ebitmap.h +2
-0@@ -41,6 +42,19 @@ static inline unsigned int ebitmap_start(struct ebitmap *e,return ebitmap_startbit (e); } +static inline unsigned int ebitmap_start_positive(struct ebitmap *e, + struct ebitmap_node **n) I suspect we could just make these all "static" (not explicitly inline)Quoted 2 lines
and let the compiler do the right thing. That seemed to be the trend upstream and guidance from arjan.
How should we do the explicitly inlined static functions used as stubs?
Quoted 3 lines
For example,
ebitmap_netlbl_export()when NetLabel is not enabled is defined as explicitly inlined function which always returns-ENOMEM, however, these are also declarations of function when NetLabel is enabled.
Ah, never mind - as these are defined in the header file, they can stay static inline.
Quoted 27 lines
Quoted 10 lines
<snip>
static inline int ebitmap_node_get_bit(structebitmap_node* n,security/selinux/ss/ebitmap.h +2
-1unsigned int bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) +unsigned int ofs = (bit - n->startbit) %EBITMAP_UNIT_SIZE ; +unsigned int index = (bit - n->startbit) /EBITMAP_UNIT_SIZE ;Possibly the computation of (ofs,index) should be a common macro since it is done in several of these functions.
I added
EBITMAP_NODE_INDEX(node,bit)andEBITMAP_NODE_OFFSET(node,bit)to compute them.Quoted 4 lines
security/selinux/ss/ebitmap.h +2
-0+ +if (index <EBITMAP_UNIT_NUMS && (n->maps[index] & (EBITMAP_BIT << ofs)))Possibly
BUG_ON(index >= EBITMAP_UNIT_NUMS)instead of silently returning 0 in that case?It is good idea indeed.
All caller ofebitmap_node_get_bit()always confirms 'bit' is in the range ofebitmap_node. If the index oversEBITMAP_UNIT_NUMS, it is a bug surely.Quoted 5 lines
security/selinux/ss/ebitmap.h +4
-0+#define ebitmap_for_each_bit (e, n, bit) \ + for (bit = ebitmap_start(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next(&n, bit)) \
Quoted 6 lines
Quoted 2 lines
Ideally we'd kill off all uses of
ebitmap_for_each_bitand use the _positive_ form in all cases, although I see that would require some changes to the mls logic.
ebitmap_start,ebitmap_nextandebitmap_for_each_bitare dropped. The rest of codes usingebitmap_for_each_bit(), inss/mls.c, are also replaced with _positive_ version.
Looks like you've left ebitmap_for_each_bit defined even though no longer used in ebitmap.h.
Quoted 29 lines
Quoted 29 lines
security/selinux/ss/ebitmap.h +4
-0+#define ebitmap_for_each_positive_bit (e, n, bit) \ + for (bit = ebitmap_start_positive(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next_positive(e, &n, bit)) \int ebitmap_cmp (struct ebitmap *e1,struct ebitmap *e2);int ebitmap_cpy (struct ebitmap *dst,struct ebitmap *src);security/selinux/ss/mls.c +2
-11@@ -190,17 +190,17 @@ int mls_context_isvalid(struct policydb *p, struct context *c)if (!levdatum)return 0 ; -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (i > p->p_cats.nprim) -return 0 ; -if (!ebitmap_get_bit (&levdatum->level->cat, i)) -/* -* Category may not be associated with -* sensitivity in low level. -*/ -return 0 ; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +// BUG_ON(!ebitmap_node_get_bit(node, i));
Quoted 3 lines
Quoted 1 line
Drop these BUG_ON's out, or uncomment them if you want to keep them for now for testing purposes.
I dropped the
BUG_ON()to confirm each bit is actually positive.
Ok, looks reasonable. Please run it through ./scripts/checkpatch.pl and fix up the minor issues it reports, then post a clean message with a suitable description and the patch inline.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
- snip -
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
(quoted diff) +2
-0+static inline unsigned int ebitmap_start_positive(struct ebitmap *e, + struct ebitmap_node **n)I suspect we could just make these all "static" (not explicitly inline) and let the compiler do the right thing. That seemed to be the trend upstream and guidance from arjan.
How should we do the explicitly inlined static functions used as stubs?
Quoted 6 lines
Quoted 3 lines
For example,
ebitmap_netlbl_export()when NetLabel is not enabled is defined as explicitly inlined function which always returns-ENOMEM, however, these are also declarations of function when NetLabel is enabled.Ah, never mind - as these are defined in the header file, they can stay static inline.
OK. I'll submit a patch to clean up non-stub static inline functions next to this patch.
- snip -
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +4
-0+#define ebitmap_for_each_bit(e, n, bit) \ + for (bit = ebitmap_start(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next(&n, bit)) \
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Ideally we'd kill off all uses of
ebitmap_for_each_bitand use the _positive_ form in all cases, although I see that would require some changes to the mls logic.
ebitmap_start,ebitmap_nextandebitmap_for_each_bitare dropped. The rest of codes usingebitmap_for_each_bit(), inss/mls.c, are also replaced with _positive_ version.Looks like you've left
ebitmap_for_each_bitdefined even though no longer used inebitmap.h.
I misses to remove it, so its definition is also removed.
- snip -
Quoted 3 lines
Ok, looks reasonable. Please run it through
./scripts/checkpatch.pland fix up the minor issues it reports, then post a clean message with a suitable description and the patch inline.
What is your stance about warnings for "line over 80 characters" ? To resolve all of them makes harder to read source code, so I'm ignoring them in the attached version.
Rest of warnings except for them are removed.
Thanks,
Signature · 4 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> Signed-off-by: KaiGai Kohei <[email protected]>
security/selinux/ss/ebitmap.c +140 -123
@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;
@@ -104,19 +110,21 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + +if (e_startbit >= c_iter->startbit +NETLBL_CATMAP_SIZE ) { + c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + cmap_idx = (e_startbit - c_iter->startbit) /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = (e_startbit - c_iter->startbit) %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;
@@ -128,7 +136,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description:
@@ -142,36 +150,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + e_idx = (c_pos - e_iter->startbit) /EBITMAP_UNIT_SIZE ; + e_sft = (c_pos - e_iter->startbit) %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);
@@ -186,6 +203,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;
@@ -197,8 +215,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;
@@ -219,12 +239,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }
@@ -238,31 +254,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +ebitmap_node_clr_bit (n, bit); + +if (find_first_bit (n->maps,EBITMAP_SIZE ) <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }
@@ -277,12 +293,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;
@@ -316,11 +332,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);
@@ -328,85 +344,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *_n =kzalloc (sizeof (*_n),GFP_KERNEL ); +if (!_n) { +printk (KERN_ERR "security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } + _n->startbit = startbit - (startbit %EBITMAP_SIZE );/* round down */ +if (n) { + n->next = _n; + }else { + e->node = _n; + } + n = _n; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;
security/selinux/ss/ebitmap.h +65 -21
118 lines not on this page · raw message
security/selinux/ss/mls.c +58 -78
199 lines not on this page · raw message
security/selinux/ss/services.c +4 -12
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 7 lines · KaiGai Kohei
Quoted 3 lines
Ok, looks reasonable. Please run it through
./scripts/checkpatch.pland fix up the minor issues it reports, then post a clean message with a suitable description and the patch inline.What is your stance about warnings for "line over 80 characters" ? To resolve all of them makes harder to read source code, so I'm ignoring them in the attached version.
Others might have different or stronger opinions about this issue, but I would encourage you to keep the line length less than or equal to 80 characters. I know it can make for some ugly looking code in some cases but being able to see the entire line in a 80 character wide terminal/editor is worth the cost.
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 13 lines · KaiGai Kohei
- snip -
Quoted 12 lines
Quoted 11 lines
Quoted 6 lines
security/selinux/ss/ebitmap.h +2
-0+static inline unsigned int ebitmap_start_positive (struct ebitmap *e, +struct ebitmap_node **n)I suspect we could just make these all "static" (not explicitly inline) and let the compiler do the right thing. That seemed to be the trend upstream and guidance from arjan.
How should we do the explicitly inlined static functions used as stubs?
For example,
ebitmap_netlbl_export()when NetLabel is not enabled is defined as explicitly inlined function which always returns-ENOMEM, however, these are also declarations of function when NetLabel is enabled.
Quoted 5 lines
Quoted 2 lines
Ah, never mind - as these are defined in the header file, they can stay static inline.
OK. I'll submit a patch to clean up non-stub static inline functions next to this patch.
I don't think it is necessary.
Quoted 19 lines
- snip -
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +4
-0+#define ebitmap_for_each_bit(e, n, bit) \ + for (bit = ebitmap_start(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next(&n, bit)) \Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Ideally we'd kill off all uses of
ebitmap_for_each_bitand use the _positive_ form in all cases, although I see that would require some changes to the mls logic.
ebitmap_start,ebitmap_nextandebitmap_for_each_bitare dropped. The rest of codes usingebitmap_for_each_bit(), inss/mls.c, are also replaced with _positive_ version.Looks like you've left
ebitmap_for_each_bitdefined even though no longer used inebitmap.h.I misses to remove it, so its definition is also removed.
- snip -
Quoted 8 lines
Quoted 3 lines
Ok, looks reasonable. Please run it through
./scripts/checkpatch.pland fix up the minor issues it reports, then post a clean message with a suitable description and the patch inline.What is your stance about warnings for "line over 80 characters" ? To resolve all of them makes harder to read source code, so I'm ignoring them in the attached version.
Rest of warnings except for them are removed.
I think we have to conform to it, and if it makes it harder to read, possibly that suggests that we need to rework the code in some way.
Quoted 6 lines
Thanks,
Signature · 4 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> Signed-off-by: KaiGai Kohei <[email protected]>
Need to make a fresh posting with appropriate subject line, text description of the patch, Signed-off-by, diffstat -p1 output, inlined patch. No residue from prior replies.
Quoted 794 lines
security/selinux/ss/ebitmap.c +140
-123@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h> @@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;@@ -104,19 +110,21 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + +if (e_startbit >= c_iter->startbit +NETLBL_CATMAP_SIZE ) { + c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + cmap_idx = (e_startbit - c_iter->startbit) /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = (e_startbit - c_iter->startbit) %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;@@ -128,7 +136,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description: @@ -142,36 +150,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + e_idx = (c_pos - e_iter->startbit) /EBITMAP_UNIT_SIZE ; + e_sft = (c_pos - e_iter->startbit) %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);@@ -186,6 +203,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;@@ -197,8 +215,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;@@ -219,12 +239,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }@@ -238,31 +254,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +ebitmap_node_clr_bit (n, bit); + +if (find_first_bit (n->maps,EBITMAP_SIZE ) <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }@@ -277,12 +293,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;@@ -316,11 +332,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);@@ -328,85 +344,86 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *_n =kzalloc (sizeof (*_n),GFP_KERNEL ); +if (!_n) { +printk (KERN_ERR "security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } + _n->startbit = startbit - (startbit %EBITMAP_SIZE );/* round down */ +if (n) { + n->next = _n; + }else { + e->node = _n; + } + n = _n; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;security/selinux/ss/ebitmap.h +65
-21@@ -16,14 +16,15 @@#include <net/netlabel.h> -#define MAPTYPE u64/* portion of bitmap in each node */ -#define MAPSIZE (sizeof(MAPTYPE) * 8)/* number of bits in node bitmap */ -#define MAPBIT 1ULL/* a bit in the node bitmap */ +#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long)) +#define EBITMAP_UNIT_SIZE BITS_PER_LONG +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) +#define EBITMAP_BIT 1ULLstruct ebitmap_node { -u32 startbit;/* starting position in the total bitmap */ -MAPTYPE map;/* this node's portion of the bitmap */ struct ebitmap_node *next; +unsigned long maps[EBITMAP_UNIT_NUMS ]; +u32 startbit; };struct ebitmap {@@ -34,11 +35,17 @@ struct ebitmap {#define ebitmap_length (e) ((e)->highbit)#define ebitmap_startbit (e) ((e)->node ? (e)->node->startbit : 0) -static inline unsigned int ebitmap_start (struct ebitmap *e, -struct ebitmap_node **n) +static inline unsigned int ebitmap_start_positive (struct ebitmap *e, +struct ebitmap_node **n) { - *n = e->node; -return ebitmap_startbit (e); +unsigned int ofs; + +for (*n = e->node; *n; *n = (*n)->next) { + ofs =find_first_bit ((*n)->maps,EBITMAP_SIZE ); +if (ofs <EBITMAP_SIZE ) +return (*n)->startbit + ofs; + } +return ebitmap_length (e); }static inline void ebitmap_init (struct ebitmap *e)@@ -46,28 +53,65 @@ static inline void ebitmap_init(struct ebitmap *e)memset (e,0 ,sizeof (*e)); } -static inline unsigned int ebitmap_next (struct ebitmap_node **n, -unsigned int bit) +static inline unsigned int ebitmap_next_positive (struct ebitmap *e, +struct ebitmap_node **n, +unsigned int bit) { -if ((bit == ((*n)->startbit +MAPSIZE -1 )) && - (*n)->next) { - *n = (*n)->next; -return (*n)->startbit; - } +unsigned int ofs; + + ofs =find_next_bit ((*n)->maps,EBITMAP_SIZE , bit - (*n)->startbit +1 ); +if (ofs <EBITMAP_SIZE ) +return ofs + (*n)->startbit; -return (bit+1 ); +for (*n = (*n)->next; *n; *n = (*n)->next) { + ofs =find_first_bit ((*n)->maps,EBITMAP_SIZE ); +if (ofs <EBITMAP_SIZE ) +return ofs + (*n)->startbit; + } +return ebitmap_length (e); } -static inline int ebitmap_node_get_bit (struct ebitmap_node * n, +#define EBITMAP_NODE_INDEX (node, bit) \ + (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE) +#define EBITMAP_NODE_OFFSET (node, bit) \ + (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE) + +static inline int ebitmap_node_get_bit (struct ebitmap_node *n,unsigned int bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); +if ((n->maps[index] & (EBITMAP_BIT << ofs)))return 1 ;return 0 ; } -#define ebitmap_for_each_bit (e, n, bit) \ - for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ +static inline void ebitmap_node_set_bit (struct ebitmap_node *n, +unsigned int bit) +{ +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); + n->maps[index] |= (EBITMAP_BIT << ofs); +} + +static inline void ebitmap_node_clr_bit (struct ebitmap_node *n, +unsigned int bit) +{ +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); + n->maps[index] &= ~(EBITMAP_BIT << ofs); +} + +#define ebitmap_for_each_positive_bit (e, n, bit) \ + for (bit = ebitmap_start_positive(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next_positive(e, &n, bit)) \int ebitmap_cmp (struct ebitmap *e1,struct ebitmap *e2);int ebitmap_cpy (struct ebitmap *dst,struct ebitmap *src);security/selinux/ss/mls.c +58
-78@@ -34,7 +34,7 @@*/ int mls_compute_context_len (struct context * context) { -int i, l, len, range; +int i, l, len, head, prev;struct ebitmap_node *node;if (!selinux_mls_enabled)@@ -42,31 +42,26 @@ int mls_compute_context_len(struct context * context) len =1 ;/* for the beginning ":" */ for (l =0 ; l <2 ; l++) { - range =0 ; len +=strlen (policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); -ebitmap_for_each_bit (&context->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (range) { - range++; -continue ; - } - +/* categories */ + head =-2 ; + prev =-2 ; +ebitmap_for_each_positive_bit (&context->range.level[l].cat, node, i) { +if (i - prev >1 ) { +/* one or more negative bits are skipped, at least. */ +if (head != prev) + len +=strlen (policydb.p_cat_val_to_name[prev]) +1 ; len +=strlen (policydb.p_cat_val_to_name[i]) +1 ; - range++; - }else { -if (range >1 ) - len +=strlen (policydb.p_cat_val_to_name[i -1 ]) +1 ; - range =0 ; + head = i; } + prev = i; } -/* Handle case where last category is the end of range */ -if (range >1 ) - len +=strlen (policydb.p_cat_val_to_name[i -1 ]) +1 ; - +if (prev != head) + len +=strlen (policydb.p_cat_val_to_name[prev]) +1 ;if (l ==0 ) {if (mls_level_eq (&context->range.level[0 ], - &context->range.level[1 ])) + &context->range.level[1 ]))break ;else len++;@@ -85,7 +80,7 @@ void mls_sid_to_context(struct context *context, char **scontext) {char *scontextp; -int i, l, range, wrote_sep; +int i, l, head, prev;struct ebitmap_node *node;if (!selinux_mls_enabled)@@ -97,61 +92,50 @@ void mls_sid_to_context(struct context *context, scontextp++;for (l =0 ; l <2 ; l++) { - range =0 ; - wrote_sep =0 ;strcpy (scontextp, policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); - scontextp +=strlen (policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); + scontextp +=strlen (scontextp);/* categories */ -ebitmap_for_each_bit (&context->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (range) { - range++; -continue ; - } - -if (!wrote_sep) { - *scontextp++ =':' ; - wrote_sep =1 ; - }else - *scontextp++ =',' ; -strcpy (scontextp, policydb.p_cat_val_to_name[i]); - scontextp +=strlen (policydb.p_cat_val_to_name[i]); - range++; - }else { -if (range >1 ) { -if (range >2 ) + head =-2 ; + prev =-2 ; +ebitmap_for_each_positive_bit (&context->range.level[l].cat, node, i) { +if (i - prev >1 ) { +/* one or more negative bits are skipped, at least. */ +if (prev != head) { +if (prev - head >1 ) *scontextp++ ='.' ;else *scontextp++ =',' ; - -strcpy (scontextp, policydb.p_cat_val_to_name[i -1 ]); - scontextp +=strlen (policydb.p_cat_val_to_name[i -1 ]); +strcpy (scontextp, policydb.p_cat_val_to_name[prev]); + scontextp +=strlen (scontextp); } - range =0 ; +if (prev <0 ) + *scontextp++ =':' ; +else + *scontextp++ =',' ; +strcpy (scontextp, policydb.p_cat_val_to_name[i]); + scontextp +=strlen (scontextp); + head = i; } + prev = i; } -/* Handle case where last category is the end of range */ -if (range >1 ) { -if (range >2 ) +if (prev != head) { +if (prev - head >1 ) *scontextp++ ='.' ;else *scontextp++ =',' ; - -strcpy (scontextp, policydb.p_cat_val_to_name[i -1 ]); - scontextp +=strlen (policydb.p_cat_val_to_name[i -1 ]); +strcpy (scontextp, policydb.p_cat_val_to_name[prev]); + scontextp +=strlen (scontextp); }if (l ==0 ) {if (mls_level_eq (&context->range.level[0 ], &context->range.level[1 ]))break ; -else { - *scontextp ='-' ; - scontextp++; - } +else + *scontextp++ ='-' ; } }@@ -190,17 +174,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)if (!levdatum)return 0 ; -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (i > p->p_cats.nprim) -return 0 ; -if (!ebitmap_get_bit (&levdatum->level->cat, i)) -/* -* Category may not be associated with -* sensitivity in low level. -*/ -return 0 ; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +if (i > p->p_cats.nprim) +return 0 ; +if (!ebitmap_get_bit (&levdatum->level->cat, i)) +/* +* Category may not be associated with +* sensitivity in low level. +*/ +return 0 ; } }@@ -485,18 +467,16 @@ int mls_convert_context(struct policydb *oldp, c->range.level[l].sens = levdatum->level->sens;ebitmap_init (&bitmap); -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -int rc; - - catdatum =hashtab_search (newp->p_cats.table, - oldp->p_cat_val_to_name[i]); -if (!catdatum) -return -EINVAL ; - rc =ebitmap_set_bit (&bitmap, catdatum->value -1 ,1 ); -if (rc) -return rc; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +int rc; + + catdatum =hashtab_search (newp->p_cats.table, + oldp->p_cat_val_to_name[i]); +if (!catdatum) +return -EINVAL ; + rc =ebitmap_set_bit (&bitmap, catdatum->value -1 ,1 ); +if (rc) +return rc; }ebitmap_destroy (&c->range.level[l].cat); c->range.level[l].cat = bitmap;security/selinux/ss/services.c +4
-13@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon)) --This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
PATCH 1/1 Improve SELinux performance when AVC misses.
Quoted 9 lines
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
For example,
ebitmap_netlbl_export()when NetLabel is not enabled is defined as explicitly inlined function which always returns-ENOMEM, however, these are also declarations of function when NetLabel is enabled.Ah, never mind - as these are defined in the header file, they can stay static inline.
OK. I'll submit a patch to clean up non-stub static inline functions next to this patch.
I don't think it is necessary.
Sorry, I might misread your suggestion.
Quoted 10 lines
Quoted 7 lines
Quoted 3 lines
Ok, looks reasonable. Please run it through
./scripts/checkpatch.pland fix up the minor issues it reports, then post a clean message with a suitable description and the patch inline.What is your stance about warnings for "line over 80 characters" ? To resolve all of them makes harder to read source code, so I'm ignoring them in the attached version.
Rest of warnings except for them are removed.I think we have to conform to it, and if it makes it harder to read, possibly that suggests that we need to rework the code in some way.
I'm preparing another version of patch which does not contain any "line over 80 characters" warning. Please wait for a while.
Quoted 3 lines
Need to make a fresh posting with appropriate subject line, text description of the patch, Signed-off-by, diffstat -p1 output, inlined patch. No residue from prior replies.
OK, the following part is a fresh patch.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 5 lines
Quoted 2 lines
I think we have to conform to it, and if it makes it harder to read, possibly that suggests that we need to rework the code in some way.
I'm preparing another version of patch which does not contain any "line over 80 characters" warning. Please wait for a while.
The following part is the patch which does not contain any "line over 80 characters" warnings.
--------
[PATCH] Improve SELinux performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on any positive bit on the given ebitmap, to improve its performance using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse in performance aspect.
This logic is most frequestly used to compute a new AVC entry, so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get suitable for using find_next_bit() which is fasted than iteration of shift and logical operation, and to maximize memory usage allocated from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation in ss/service.c and ss/mls.c. Some of related implementation are changed, however, there is no incompatibility with the previous version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we access many files which have different security context one after another. The number is more than /selinux/avc/cache_threshold, so any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]
--- security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++----------------- security/selinux/ss/ebitmap.h | 87 ++++++++++--- security/selinux/ss/mls.c | 156 +++++++++++------------ security/selinux/ss/services.c | 16 +-- 4 files changed, 303 insertions(+), 237 deletions(-)
security/selinux/ss/ebitmap.c +158 -123
@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int delta, e_startbit, c_endbit; + + e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + c_endbit = c_iter->startbit +NETLBL_CATMAP_SIZE ; +if (e_startbit >= c_endbit) { + c_iter->next + =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit + = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + delta = e_startbit - c_iter->startbit; + cmap_idx = delta /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = delta %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] + |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;
@@ -128,7 +142,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +unsigned int delta; +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter + || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit + = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + delta = c_pos - e_iter->startbit; + e_idx = delta /EBITMAP_UNIT_SIZE ; + e_sft = delta %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);
@@ -186,6 +214,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +unsigned int s; + +ebitmap_node_clr_bit (n, bit); + + s =find_first_bit (n->maps,EBITMAP_SIZE ); +if (s <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit + +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *_n; + _n =kzalloc (sizeof (*_n),GFP_KERNEL ); +if (!_n) { +printk (KERN_ERR +"security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } +/* round down */ + _n->startbit = startbit - (startbit %EBITMAP_SIZE ); +if (n) { + n->next = _n; + }else { + e->node = _n; + } + n = _n; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;
security/selinux/ss/ebitmap.h +66 -21
119 lines not on this page · raw message
security/selinux/ss/mls.c +75 -81
217 lines not on this page · raw message
security/selinux/ss/services.c +4 -12
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 7 lines · KaiGai Kohei
Quoted 4 lines
Quoted 2 lines
I think we have to conform to it, and if it makes it harder to read, possibly that suggests that we need to rework the code in some way.
I'm preparing another version of patch which does not contain any "line over 80 characters" warning. Please wait for a while.
The following part is the patch which does not contain any "line over 80 characters" warnings.
The following part is a result of diff between the previous patch which contains 80-char warnings and the latest one without them.
I think it is better than I expected.
However, there are several ugly manner like as:
-+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
++ c_iter->startbit
++ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
If both side of the formula is in a same line, the width of the line get overs the 80-char limitation.
++ char *nm;
:++ if (head != prev) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
++ }
If the temporary char * variable is named as "cat_name", the above longest line overs 80-char limitation, so I named it as "nm".
This naming may be unclear for its purpose.
Thanks,
[kaigai@saba ~]$ diff -NU3 ebitmap-bitops.patch ebitmap-bitops.less-than-80char.patch
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
-index ce492a6..3a60186 100644
+index ce492a6..5643bdd 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
@@ -53,7 +59,7 @@
if (e_iter == NULL) {
*catmap = NULL;
-@@ -104,19 +110,21 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, +@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) {
@@ -66,18 +72,24 @@
- c_iter->startbit = e_iter->startbit &
- ~(NETLBL_CATMAP_SIZE - 1);
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
-+ unsigned int e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
++ unsigned int delta, e_startbit, c_endbit;
+
-+ if (e_startbit >= c_iter->startbit + NETLBL_CATMAP_SIZE) {
-+ c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
++ e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
++ c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
++ if (e_startbit >= c_endbit) {
++ c_iter->next
++ = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (c_iter->next == NULL)
+ goto netlbl_export_failure;
+ c_iter = c_iter->next;
-+ c_iter->startbit = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
++ c_iter->startbit
++ = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
-+ cmap_idx = (e_startbit - c_iter->startbit) / NETLBL_CATMAP_MAPSIZE;
-+ cmap_sft = (e_startbit - c_iter->startbit) % NETLBL_CATMAP_MAPSIZE;
-+ c_iter->bitmap[cmap_idx] |= e_iter->maps[cmap_idx] << cmap_sft;
++ delta = e_startbit - c_iter->startbit;
++ cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
++ cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
++ c_iter->bitmap[cmap_idx]
++ |= e_iter->maps[cmap_idx] << cmap_sft;
+ e_iter = e_iter->next;
}
- cmap_idx = (e_iter->startbit - c_iter->startbit) /
@@ -87,7 +99,7 @@
}
return 0;
-@@ -128,7 +136,7 @@ netlbl_export_failure:
+@@ -128,7 +142,7 @@ netlbl_export_failure:
/**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
@@ -96,7 +108,7 @@
* @catmap: the NetLabel category bitmap
*
* Description:
-@@ -142,36 +150,45 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, +@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap;
@@ -118,6 +130,7 @@
do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
- if (c_iter->bitmap[c_idx] == 0)
++ unsigned int delta;
+ u64 map = c_iter->bitmap[c_idx];
+
+ if (!map)
@@ -135,20 +148,24 @@
- e_iter->startbit = c_iter->startbit +
- NETLBL_CATMAP_MAPSIZE * c_idx;
- e_iter->map = c_iter->bitmap[c_idx];
-+ c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE;
-+ if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
++ c_pos = c_iter->startbit
++ + c_idx * NETLBL_CATMAP_MAPSIZE;
++ if (!e_iter
++ || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
+ e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+ if (!e_iter)
+ goto netlbl_import_failure;
-+ e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE);
++ e_iter->startbit
++ = c_pos - (c_pos % EBITMAP_SIZE);
+ if (emap_prev == NULL)
+ ebmap->node = e_iter;
+ else
+ emap_prev->next = e_iter;
+ emap_prev = e_iter;
+ }
-+ e_idx = (c_pos - e_iter->startbit) / EBITMAP_UNIT_SIZE;
-+ e_sft = (c_pos - e_iter->startbit) % EBITMAP_UNIT_SIZE;
++ delta = c_pos - e_iter->startbit;
++ e_idx = delta / EBITMAP_UNIT_SIZE;
++ e_sft = delta % EBITMAP_UNIT_SIZE;
+ while (map) {
+ e_iter->maps[e_idx++] |= map & (-1UL);
+ map >>= EBITMAP_UNIT_SIZE;
@@ -162,7 +179,7 @@
else
ebitmap_destroy(ebmap);
-@@ -186,6 +203,7 @@ netlbl_import_failure:
+@@ -186,6 +214,7 @@ netlbl_import_failure:
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) {
struct ebitmap_node *n1, *n2;
@@ -170,7 +187,7 @@
if (e1->highbit < e2->highbit)
return 0;
-@@ -197,8 +215,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) +@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next;
continue;
}
@@ -183,7 +200,7 @@
n1 = n1->next;
n2 = n2->next;
-@@ -219,12 +239,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) +@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node;
while (n && (n->startbit <= bit)) {
@@ -198,7 +215,7 @@
n = n->next;
}
-@@ -238,31 +254,31 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) +@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
@@ -222,9 +239,12 @@
- else
- e->highbit = 0;
- }
++ unsigned int s;
++
+ ebitmap_node_clr_bit(n, bit);
+
-+ if (find_first_bit(n->maps, EBITMAP_SIZE) < EBITMAP_SIZE)
++ s = find_first_bit(n->maps, EBITMAP_SIZE);
++ if (s < EBITMAP_SIZE)
+ return 0;
+
+ /* drop this node from the bitmap */
@@ -235,7 +255,8 @@
+ */
if (prev)
- prev->next = n->next;
-+ e->highbit = prev->startbit + EBITMAP_SIZE;
++ e->highbit = prev->startbit
++ + EBITMAP_SIZE;
else
- e->node = n->next;
-
@@ -250,7 +271,7 @@
}
return 0;
}
-@@ -277,12 +293,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) +@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new)
return -ENOMEM;
@@ -266,7 +287,7 @@
if (prev) {
new->next = prev->next;
-@@ -316,11 +332,11 @@ void ebitmap_destroy(struct ebitmap *e) +@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
@@ -282,7 +303,7 @@
ebitmap_init(e);
-@@ -328,85 +344,86 @@ int ebitmap_read(struct ebitmap *e, void *fp) +@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0)
goto out;
@@ -354,13 +375,16 @@
+ }
+
+ if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
-+ struct ebitmap_node *_n = kzalloc(sizeof(*_n), GFP_KERNEL);
++ struct ebitmap_node *_n;
++ _n = kzalloc(sizeof(*_n), GFP_KERNEL);
+ if (!_n) {
-+ printk(KERN_ERR "security: ebitmap: out of memory\n");
++ printk(KERN_ERR
++ "security: ebitmap: out of memory\n");
+ rc = -ENOMEM;
+ goto bad;
+ }
-+ _n->startbit = startbit - (startbit % EBITMAP_SIZE); /* round down */
++ /* round down */
++ _n->startbit = startbit - (startbit % EBITMAP_SIZE);
+ if (n) {
+ n->next = _n;
+ } else {
@@ -417,17 +441,18 @@
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
-index 1270e34..417053e 100644
+index 1270e34..e38a327 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
-@@ -16,14 +16,15 @@
+@@ -16,14 +16,16 @@
#include <net/netlabel.h>
-#define MAPTYPE u64 /* portion of bitmap in each node */
-#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
-#define MAPBIT 1ULL /* a bit in the node bitmap */
-+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) / sizeof(unsigned long))
++#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
++ / sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1ULL
@@ -441,7 +466,7 @@
};
struct ebitmap {
-@@ -34,11 +35,17 @@ struct ebitmap {
+@@ -34,11 +36,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
@@ -463,7 +488,7 @@
}
static inline void ebitmap_init(struct ebitmap *e)
-@@ -46,28 +53,65 @@ static inline void ebitmap_init(struct ebitmap *e) +@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
@@ -542,56 +567,67 @@
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
-index 4a8bab2..27ef5eb 100644
+index 4a8bab2..9a11dea 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
-@@ -34,7 +34,7 @@
+@@ -34,7 +34,9 @@
*/
int mls_compute_context_len(struct context * context) {
- int i, l, len, range;
+ int i, l, len, head, prev;
++ char *nm;
++ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
-@@ -42,31 +42,26 @@ int mls_compute_context_len(struct context * context) +@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) {
- range = 0;
- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
-
+- len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); +-
- ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
- if (ebitmap_node_get_bit(node, i)) {
- if (range) {
- range++;
- continue;
- }
--
-+ /* categories */
-+ head = -2;
-+ prev = -2;
-+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
-+ if (i - prev > 1) {
-+ /* one or more negative bits are skipped, at least. */
-+ if (head != prev)
-+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
++ int index_sens = context->range.level[l].sens;
++ len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
+
+- len += strlen(policydb.p_cat_val_to_name[i]) + 1;
- range++;
- } else {
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
- range = 0;
++ /* categories */
++ head = -2;
++ prev = -2;
++ e = &context->range.level[l].cat;
++ ebitmap_for_each_positive_bit(e, node, i) {
++ if (i - prev > 1) {
++ /* one or more negative bits are skipped */
++ if (head != prev) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
++ }
++ nm = policydb.p_cat_val_to_name[i];
++ len += strlen(nm) + 1;
+ head = i;
}
+ prev = i;
++ }
++ if (prev != head) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
}
- /* Handle case where last category is the end of range */
- if (range > 1)
- len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
-
-+ if (prev != head)
-+ len += strlen(policydb.p_cat_val_to_name[prev]) + 1;
if (l == 0) {
if (mls_level_eq(&context->range.level[0],
- &context->range.level[1]))
@@ -599,16 +635,19 @@
break;
else
len++;
-@@ -85,7 +80,7 @@ void mls_sid_to_context(struct context *context, +@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
+ void mls_sid_to_context(struct context *context,
char **scontext)
{
- char *scontextp;
+- char *scontextp;
- int i, l, range, wrote_sep;
++ char *scontextp, *nm;
+ int i, l, head, prev;
++ struct ebitmap *e;
struct ebitmap_node *node;
if (!selinux_mls_enabled)
-@@ -97,61 +92,50 @@ void mls_sid_to_context(struct context *context, +@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
scontextp++;
for (l = 0; l < 2; l++) {
@@ -640,9 +679,10 @@
- if (range > 2)
+ head = -2;
+ prev = -2;
-+ ebitmap_for_each_positive_bit(&context->range.level[l].cat, node, i) {
++ e = &context->range.level[l].cat;
++ ebitmap_for_each_positive_bit(e, node, i) {
+ if (i - prev > 1) {
-+ /* one or more negative bits are skipped, at least. */
++ /* one or more negative bits are skipped */
+ if (prev != head) {
+ if (prev - head > 1)
*scontextp++ = '.';
@@ -651,16 +691,18 @@
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
-+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
-+ scontextp += strlen(scontextp);
++ nm = policydb.p_cat_val_to_name[prev];
++ strcpy(scontextp, nm);
++ scontextp += strlen(nm);
}
- range = 0;
+ if (prev < 0)
+ *scontextp++ = ':';
+ else
+ *scontextp++ = ',';
-+ strcpy(scontextp, policydb.p_cat_val_to_name[i]);
-+ scontextp += strlen(scontextp);
++ nm = policydb.p_cat_val_to_name[i];
++ strcpy(scontextp, nm);
++ scontextp += strlen(nm);
+ head = i;
}
+ prev = i;
@@ -677,8 +719,9 @@
-
- strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
- scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
-+ strcpy(scontextp, policydb.p_cat_val_to_name[prev]);
-+ scontextp += strlen(scontextp);
++ nm = policydb.p_cat_val_to_name[prev];
++ strcpy(scontextp, nm);
++ scontextp += strlen(nm);
}
if (l == 0) {
@@ -694,7 +737,7 @@
}
}
-@@ -190,17 +174,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c) +@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum)
return 0;
@@ -721,7 +764,7 @@
}
}
-@@ -485,18 +467,16 @@ int mls_convert_context(struct policydb *oldp, +@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
Signature · 7 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 7 lines · KaiGai Kohei
However, there are several ugly manner like as:
-+
c_iter->startbit=e_startbit& ~(NETLBL_CATMAP_SIZE - 1);
++c_iter->startbit
++ =e_startbit& ~(NETLBL_CATMAP_SIZE - 1);
If both side of the formula is in a same line, the width of the line get overs the 80-char limitation.
This is pretty common, so don't worry.
Quoted 4 lines
++ char *nm;
:Quoted 8 lines
++ if (head != prev) {
++ nm = policydb.p_cat_val_to_name[prev];
++ len += strlen(nm) + 1;
++ }If the temporary char * variable is named as "
cat_name", the above longest line overs 80-char limitation, so I named it as "nm".
This naming may be unclear for its purpose.
I think it's better to keep the 80 column limit here.
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);
Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 4 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.
Thanks,
Signature · 48 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> [PATCH] Improve SELinux performance when AVC misses. * We add ebitmap_for_each_positive_bit() which enables to walk on any positive bit on the given ebitmap, to improve its performance using common bit-operations defined in linux/bitops.h. In the previous version, this logic was implemented using a combination of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse in performance aspect. This logic is most frequestly used to compute a new AVC entry, so this patch can improve SELinux performance when AVC misses are happen. * struct ebitmap_node is redefined as an array of "unsigned long", to get suitable for using find_next_bit() which is fasted than iteration of shift and logical operation, and to maximize memory usage allocated from general purpose slab. * Any ebitmap_for_each_bit() are repleced by the new implementation in ss/service.c and ss/mls.c. Some of related implementation are changed, however, there is no incompatibility with the previous version. * The width of any new line are less or equal than 80-chars. The following benchmark shows the effect of this patch, when we access many files which have different security context one after another. The number is more than /selinux/avc/cache_threshold, so any access always causes AVC misses. selinux-2.6 selinux-2.6-ebitmap AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s] Signed-off-by: KaiGai Kohei <[email protected]> --- security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++----------------- security/selinux/ss/ebitmap.h | 87 ++++++++++--- security/selinux/ss/mls.c | 156 +++++++++++------------ security/selinux/ss/services.c | 16 +-- 4 files changed, 303 insertions(+), 237 deletions(-)
security/selinux/ss/ebitmap.c +158 -123
@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int delta, e_startbit, c_endbit; + + e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + c_endbit = c_iter->startbit +NETLBL_CATMAP_SIZE ; +if (e_startbit >= c_endbit) { + c_iter->next + =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit + = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + delta = e_startbit - c_iter->startbit; + cmap_idx = delta /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = delta %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] + |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;
@@ -128,7 +142,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +unsigned int delta; +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter + || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit + = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + delta = c_pos - e_iter->startbit; + e_idx = delta /EBITMAP_UNIT_SIZE ; + e_sft = delta %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);
@@ -186,6 +214,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +unsigned int s; + +ebitmap_node_clr_bit (n, bit); + + s =find_first_bit (n->maps,EBITMAP_SIZE ); +if (s <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit + +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *tmp; + tmp =kzalloc (sizeof (*tmp),GFP_KERNEL ); +if (!tmp) { +printk (KERN_ERR +"security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } +/* round down */ + tmp->startbit = startbit - (startbit %EBITMAP_SIZE ); +if (n) { + n->next = tmp; + }else { + e->node = tmp; + } + n = tmp; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;
security/selinux/ss/ebitmap.h +66 -21
119 lines not on this page · raw message
security/selinux/ss/mls.c +75 -81
217 lines not on this page · raw message
security/selinux/ss/services.c +4 -12
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 10 lines · KaiGai Kohei
Quoted 6 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.
Seems to be damaged, or at least doesn't apply for me. What is it relative to?
Quoted 882 lines
Thanks,
Signature · 48 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> [PATCH] Improve SELinux performance when AVC misses. * We add ebitmap_for_each_positive_bit() which enables to walk on any positive bit on the given ebitmap, to improve its performance using common bit-operations defined in linux/bitops.h. In the previous version, this logic was implemented using a combination of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse in performance aspect. This logic is most frequestly used to compute a new AVC entry, so this patch can improve SELinux performance when AVC misses are happen. * struct ebitmap_node is redefined as an array of "unsigned long", to get suitable for using find_next_bit() which is fasted than iteration of shift and logical operation, and to maximize memory usage allocated from general purpose slab. * Any ebitmap_for_each_bit() are repleced by the new implementation in ss/service.c and ss/mls.c. Some of related implementation are changed, however, there is no incompatibility with the previous version. * The width of any new line are less or equal than 80-chars. The following benchmark shows the effect of this patch, when we access many files which have different security context one after another. The number is more than /selinux/avc/cache_threshold, so any access always causes AVC misses. selinux-2.6 selinux-2.6-ebitmap AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s] Signed-off-by: KaiGai Kohei <[email protected]> --- security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++----------------- security/selinux/ss/ebitmap.h | 87 ++++++++++--- security/selinux/ss/mls.c | 156 +++++++++++------------ security/selinux/ss/services.c | 16 +-- 4 files changed, 303 insertions(+), 237 deletions(-)security/selinux/ss/ebitmap.c +158
-123@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h> @@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int delta, e_startbit, c_endbit; + + e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + c_endbit = c_iter->startbit +NETLBL_CATMAP_SIZE ; +if (e_startbit >= c_endbit) { + c_iter->next + =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit + = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + delta = e_startbit - c_iter->startbit; + cmap_idx = delta /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = delta %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] + |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;@@ -128,7 +142,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description: @@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +unsigned int delta; +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter + || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit + = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + delta = c_pos - e_iter->startbit; + e_idx = delta /EBITMAP_UNIT_SIZE ; + e_sft = delta %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);@@ -186,6 +214,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +unsigned int s; + +ebitmap_node_clr_bit (n, bit); + + s =find_first_bit (n->maps,EBITMAP_SIZE ); +if (s <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit + +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *tmp; + tmp =kzalloc (sizeof (*tmp),GFP_KERNEL ); +if (!tmp) { +printk (KERN_ERR +"security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } +/* round down */ + tmp->startbit = startbit - (startbit %EBITMAP_SIZE ); +if (n) { + n->next = tmp; + }else { + e->node = tmp; + } + n = tmp; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;security/selinux/ss/ebitmap.h +66
-21@@ -16,14 +16,16 @@#include <net/netlabel.h> -#define MAPTYPE u64/* portion of bitmap in each node */ -#define MAPSIZE (sizeof(MAPTYPE) * 8)/* number of bits in node bitmap */ -#define MAPBIT 1ULL/* a bit in the node bitmap */ +#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \ + / sizeof(unsigned long)) +#define EBITMAP_UNIT_SIZE BITS_PER_LONG +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) +#define EBITMAP_BIT 1ULLstruct ebitmap_node { -u32 startbit;/* starting position in the total bitmap */ -MAPTYPE map;/* this node's portion of the bitmap */ struct ebitmap_node *next; +unsigned long maps[EBITMAP_UNIT_NUMS ]; +u32 startbit; };struct ebitmap {@@ -34,11 +36,17 @@ struct ebitmap {#define ebitmap_length (e) ((e)->highbit)#define ebitmap_startbit (e) ((e)->node ? (e)->node->startbit : 0) -static inline unsigned int ebitmap_start (struct ebitmap *e, -struct ebitmap_node **n) +static inline unsigned int ebitmap_start_positive (struct ebitmap *e, +struct ebitmap_node **n) { - *n = e->node; -return ebitmap_startbit (e); +unsigned int ofs; + +for (*n = e->node; *n; *n = (*n)->next) { + ofs =find_first_bit ((*n)->maps,EBITMAP_SIZE ); +if (ofs <EBITMAP_SIZE ) +return (*n)->startbit + ofs; + } +return ebitmap_length (e); }static inline void ebitmap_init (struct ebitmap *e)@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)memset (e,0 ,sizeof (*e)); } -static inline unsigned int ebitmap_next (struct ebitmap_node **n, -unsigned int bit) +static inline unsigned int ebitmap_next_positive (struct ebitmap *e, +struct ebitmap_node **n, +unsigned int bit) { -if ((bit == ((*n)->startbit +MAPSIZE -1 )) && - (*n)->next) { - *n = (*n)->next; -return (*n)->startbit; - } +unsigned int ofs; + + ofs =find_next_bit ((*n)->maps,EBITMAP_SIZE , bit - (*n)->startbit +1 ); +if (ofs <EBITMAP_SIZE ) +return ofs + (*n)->startbit; -return (bit+1 ); +for (*n = (*n)->next; *n; *n = (*n)->next) { + ofs =find_first_bit ((*n)->maps,EBITMAP_SIZE ); +if (ofs <EBITMAP_SIZE ) +return ofs + (*n)->startbit; + } +return ebitmap_length (e); } -static inline int ebitmap_node_get_bit (struct ebitmap_node * n, +#define EBITMAP_NODE_INDEX (node, bit) \ + (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE) +#define EBITMAP_NODE_OFFSET (node, bit) \ + (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE) + +static inline int ebitmap_node_get_bit (struct ebitmap_node *n,unsigned int bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); +if ((n->maps[index] & (EBITMAP_BIT << ofs)))return 1 ;return 0 ; } -#define ebitmap_for_each_bit (e, n, bit) \ - for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ +static inline void ebitmap_node_set_bit (struct ebitmap_node *n, +unsigned int bit) +{ +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); + n->maps[index] |= (EBITMAP_BIT << ofs); +} + +static inline void ebitmap_node_clr_bit (struct ebitmap_node *n, +unsigned int bit) +{ +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); + n->maps[index] &= ~(EBITMAP_BIT << ofs); +} + +#define ebitmap_for_each_positive_bit (e, n, bit) \ + for (bit = ebitmap_start_positive(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next_positive(e, &n, bit)) \int ebitmap_cmp (struct ebitmap *e1,struct ebitmap *e2);int ebitmap_cpy (struct ebitmap *dst,struct ebitmap *src);security/selinux/ss/mls.c +75
-81@@ -34,7 +34,9 @@*/ int mls_compute_context_len (struct context * context) { -int i, l, len, range; +int i, l, len, head, prev; +char *nm; +struct ebitmap *e;struct ebitmap_node *node;if (!selinux_mls_enabled)@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context) len =1 ;/* for the beginning ":" */ for (l =0 ; l <2 ; l++) { - range =0 ; - len +=strlen (policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); - -ebitmap_for_each_bit (&context->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (range) { - range++; -continue ; - } +int index_sens = context->range.level[l].sens; + len +=strlen (policydb.p_sens_val_to_name[index_sens -1 ]); - len +=strlen (policydb.p_cat_val_to_name[i]) +1 ; - range++; - }else { -if (range >1 ) - len +=strlen (policydb.p_cat_val_to_name[i -1 ]) +1 ; - range =0 ; +/* categories */ + head =-2 ; + prev =-2 ; + e = &context->range.level[l].cat; +ebitmap_for_each_positive_bit (e, node, i) { +if (i - prev >1 ) { +/* one or more negative bits are skipped */ +if (head != prev) { + nm = policydb.p_cat_val_to_name[prev]; + len +=strlen (nm) +1 ; + } + nm = policydb.p_cat_val_to_name[i]; + len +=strlen (nm) +1 ; + head = i; } + prev = i; + } +if (prev != head) { + nm = policydb.p_cat_val_to_name[prev]; + len +=strlen (nm) +1 ; } -/* Handle case where last category is the end of range */ -if (range >1 ) - len +=strlen (policydb.p_cat_val_to_name[i -1 ]) +1 ; -if (l ==0 ) {if (mls_level_eq (&context->range.level[0 ], - &context->range.level[1 ])) + &context->range.level[1 ]))break ;else len++;@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)void mls_sid_to_context (struct context *context,char **scontext) { -char *scontextp; -int i, l, range, wrote_sep; +char *scontextp, *nm; +int i, l, head, prev; +struct ebitmap *e;struct ebitmap_node *node;if (!selinux_mls_enabled)@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context, scontextp++;for (l =0 ; l <2 ; l++) { - range =0 ; - wrote_sep =0 ;strcpy (scontextp, policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); - scontextp +=strlen (policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); + scontextp +=strlen (scontextp);/* categories */ -ebitmap_for_each_bit (&context->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (range) { - range++; -continue ; - } - -if (!wrote_sep) { - *scontextp++ =':' ; - wrote_sep =1 ; - }else - *scontextp++ =',' ; -strcpy (scontextp, policydb.p_cat_val_to_name[i]); - scontextp +=strlen (policydb.p_cat_val_to_name[i]); - range++; - }else { -if (range >1 ) { -if (range >2 ) + head =-2 ; + prev =-2 ; + e = &context->range.level[l].cat; +ebitmap_for_each_positive_bit (e, node, i) { +if (i - prev >1 ) { +/* one or more negative bits are skipped */ +if (prev != head) { +if (prev - head >1 ) *scontextp++ ='.' ;else *scontextp++ =',' ; - -strcpy (scontextp, policydb.p_cat_val_to_name[i -1 ]); - scontextp +=strlen (policydb.p_cat_val_to_name[i -1 ]); + nm = policydb.p_cat_val_to_name[prev]; +strcpy (scontextp, nm); + scontextp +=strlen (nm); } - range =0 ; +if (prev <0 ) + *scontextp++ =':' ; +else + *scontextp++ =',' ; + nm = policydb.p_cat_val_to_name[i]; +strcpy (scontextp, nm); + scontextp +=strlen (nm); + head = i; } + prev = i; } -/* Handle case where last category is the end of range */ -if (range >1 ) { -if (range >2 ) +if (prev != head) { +if (prev - head >1 ) *scontextp++ ='.' ;else *scontextp++ =',' ; - -strcpy (scontextp, policydb.p_cat_val_to_name[i -1 ]); - scontextp +=strlen (policydb.p_cat_val_to_name[i -1 ]); + nm = policydb.p_cat_val_to_name[prev]; +strcpy (scontextp, nm); + scontextp +=strlen (nm); }if (l ==0 ) {if (mls_level_eq (&context->range.level[0 ], &context->range.level[1 ]))break ; -else { - *scontextp ='-' ; - scontextp++; - } +else + *scontextp++ ='-' ; } }@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)if (!levdatum)return 0 ; -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (i > p->p_cats.nprim) -return 0 ; -if (!ebitmap_get_bit (&levdatum->level->cat, i)) -/* -* Category may not be associated with -* sensitivity in low level. -*/ -return 0 ; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +if (i > p->p_cats.nprim) +return 0 ; +if (!ebitmap_get_bit (&levdatum->level->cat, i)) +/* +* Category may not be associated with +* sensitivity in low level. +*/ +return 0 ; } }@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp, c->range.level[l].sens = levdatum->level->sens;ebitmap_init (&bitmap); -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -int rc; - - catdatum =hashtab_search (newp->p_cats.table, - oldp->p_cat_val_to_name[i]); -if (!catdatum) -return -EINVAL ; - rc =ebitmap_set_bit (&bitmap, catdatum->value -1 ,1 ); -if (rc) -return rc; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +int rc; + + catdatum =hashtab_search (newp->p_cats.table, + oldp->p_cat_val_to_name[i]); +if (!catdatum) +return -EINVAL ; + rc =ebitmap_set_bit (&bitmap, catdatum->value -1 ,1 ); +if (rc) +return rc; }ebitmap_destroy (&c->range.level[l].cat); c->range.level[l].cat = bitmap;security/selinux/ss/services.c +4
-13@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon)) --This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 4 lines · Stephen Smalley
Quoted 3 lines · KaiGai Kohei
Quoted 2 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.Seems to be damaged, or at least doesn't apply for me. What is it relative to?
I generated the patch against to the latest of James's git tree But it seems to me that all tab chatacters are translated into four white spaces, when I copied and pasted the patch. I'm sorry, it was my misoperation.
Can you receive it with tab kept in this time?
Thanks,
--------
[PATCH] Improve SELinux performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on any positive bit on the given ebitmap, to improve its performance using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse in performance aspect.
This logic is most frequestly used to compute a new AVC entry, so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get suitable for using find_next_bit() which is fasted than iteration of shift and logical operation, and to maximize memory usage allocated from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation in ss/service.c and ss/mls.c. Some of related implementation are changed, however, there is no incompatibility with the previous version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we access many files which have different security context one after another. The number is more than /selinux/avc/cache_threshold, so any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]
--- security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++----------------- security/selinux/ss/ebitmap.h | 87 ++++++++++--- security/selinux/ss/mls.c | 156 +++++++++++------------ security/selinux/ss/services.c | 16 +-- 4 files changed, 303 insertions(+), 237 deletions(-)
security/selinux/ss/ebitmap.c +158 -123
@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int delta, e_startbit, c_endbit; + + e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + c_endbit = c_iter->startbit +NETLBL_CATMAP_SIZE ; +if (e_startbit >= c_endbit) { + c_iter->next + =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit + = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + delta = e_startbit - c_iter->startbit; + cmap_idx = delta /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = delta %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] + |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;
@@ -128,7 +142,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +unsigned int delta; +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter + || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit + = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + delta = c_pos - e_iter->startbit; + e_idx = delta /EBITMAP_UNIT_SIZE ; + e_sft = delta %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);
@@ -186,6 +214,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +unsigned int s; + +ebitmap_node_clr_bit (n, bit); + + s =find_first_bit (n->maps,EBITMAP_SIZE ); +if (s <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit + +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *tmp; + tmp =kzalloc (sizeof (*tmp),GFP_KERNEL ); +if (!tmp) { +printk (KERN_ERR +"security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } +/* round down */ + tmp->startbit = startbit - (startbit %EBITMAP_SIZE ); +if (n) { + n->next = tmp; + }else { + e->node = tmp; + } + n = tmp; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;
security/selinux/ss/ebitmap.h +66 -21
119 lines not on this page · raw message
security/selinux/ss/mls.c +75 -81
217 lines not on this page · raw message
security/selinux/ss/services.c +4 -12
@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon))
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Stephen Smalley
Acked-byRe: [PATCH] Improve SELinux performance when AVC misses.
Quoted 62 lines · KaiGai Kohei
Quoted 4 lines · Stephen Smalley
Quoted 3 lines · KaiGai Kohei
Quoted 2 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.Seems to be damaged, or at least doesn't apply for me. What is it relative to?
I generated the patch against to the latest of James's git tree But it seems to me that all tab chatacters are translated into four white spaces, when I copied and pasted the patch. I'm sorry, it was my misoperation.
Can you receive it with tab kept in this time?
Thanks,
--------
[PATCH] Improve SELinux performance when AVC misses.* We add
ebitmap_for_each_positive_bit()which enables to walk on any positive bit on the given ebitmap, to improve its performance using common bit-operations defined inlinux/bitops.h.
In the previous version, this logic was implemented using a combination ofebitmap_for_each_bit()andebitmap_node_get_bit(), but is was worse in performance aspect.
This logic is most frequestly used to compute a new AVC entry, so this patch can improve SELinux performance when AVC misses are happen.
* structebitmap_nodeis redefined as an array of "unsigned long", to get suitable for usingfind_next_bit()which is fasted than iteration of shift and logical operation, and to maximize memory usage allocated from general purpose slab.
* Anyebitmap_for_each_bit()are repleced by the new implementation inss/service.candss/mls.c. Some of related implementation are changed, however, there is no incompatibility with the previous version.
* The width of any new line are less or equal than 80-chars.The following benchmark shows the effect of this patch, when we access many files which have different security context one after another. The number is more than /selinux/avc/cache_threshold, so any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s] STD: 0.265 0.019 ------------------------------------------ 1st: 22.558 [s] 8.786 [s] 2nd: 22.458 [s] 8.750 [s] 3rd: 22.478 [s] 8.754 [s] 4th: 22.724 [s] 8.745 [s] 5th: 22.918 [s] 8.748 [s] 6th: 22.905 [s] 8.764 [s] 7th: 23.238 [s] 8.726 [s] 8th: 22.822 [s] 8.729 [s]
Quoted 1 line
Signed-off-by KaiGai Kohei <[email protected]>
Quoted 845 lines
--- security/selinux/ss/ebitmap.c | 281 ++++++++++++++++++++++----------------- security/selinux/ss/ebitmap.h | 87 ++++++++++--- security/selinux/ss/mls.c | 156 +++++++++++------------ security/selinux/ss/services.c | 16 +-- 4 files changed, 303 insertions(+), 237 deletions(-)security/selinux/ss/ebitmap.c +158
-123@@ -10,6 +10,10 @@* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ +/* +* Updated: KaiGai Kohei <[email protected]> +* Applied standard bit operations to improve bitmap scanning. +*/ #include <linux/kernel.h> #include <linux/slab.h> @@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) n2 = e2->node;while (n1 && n2 && (n1->startbit == n2->startbit) && - (n1->map == n2->map)) { + !memcmp (n1->maps, n2->maps,EBITMAP_SIZE /8 )) { n1 = n1->next; n2 = n2->next; }@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)return -ENOMEM ; } new->startbit = n->startbit; - new->map = n->map; +memcpy (new->maps, n->maps,EBITMAP_SIZE /8 ); new->next =NULL ;if (prev) prev->next = new;@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, {struct ebitmap_node *e_iter = ebmap->node;struct netlbl_lsm_secattr_catmap *c_iter; -u32 cmap_idx; +u32 cmap_idx, cmap_sft; +int i; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ if (e_iter ==NULL ) { *catmap =NULL ;@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE -1 );while (e_iter !=NULL ) { -if (e_iter->startbit >= - (c_iter->startbit +NETLBL_CATMAP_SIZE )) { - c_iter->next =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); -if (c_iter->next ==NULL ) - goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit = e_iter->startbit & - ~(NETLBL_CATMAP_SIZE -1 ); +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +unsigned int delta, e_startbit, c_endbit; + + e_startbit = e_iter->startbit + i *EBITMAP_UNIT_SIZE ; + c_endbit = c_iter->startbit +NETLBL_CATMAP_SIZE ; +if (e_startbit >= c_endbit) { + c_iter->next + =netlbl_secattr_catmap_alloc (GFP_ATOMIC ); +if (c_iter->next ==NULL ) + goto netlbl_export_failure; + c_iter = c_iter->next; + c_iter->startbit + = e_startbit & ~(NETLBL_CATMAP_SIZE -1 ); + } + delta = e_startbit - c_iter->startbit; + cmap_idx = delta /NETLBL_CATMAP_MAPSIZE ; + cmap_sft = delta %NETLBL_CATMAP_MAPSIZE ; + c_iter->bitmap[cmap_idx] + |= e_iter->maps[cmap_idx] << cmap_sft; + e_iter = e_iter->next; } - cmap_idx = (e_iter->startbit - c_iter->startbit) / -NETLBL_CATMAP_MAPSIZE ; - c_iter->bitmap[cmap_idx] = e_iter->map; - e_iter = e_iter->next; }return 0 ;@@ -128,7 +142,7 @@ netlbl_export_failure:/** * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap -* @ebmap: the ebitmap to export +* @ebmap: the ebitmap to import * @catmap: the NetLabel category bitmap * * Description: @@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,struct ebitmap_node *e_iter =NULL ;struct ebitmap_node *emap_prev =NULL ;struct netlbl_lsm_secattr_catmap *c_iter = catmap; -u32 c_idx; +u32 c_idx, c_pos, e_idx, e_sft; -/* This function is a much simpler because SELinux's MAPTYPE happens -* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is -* changed from a u64 this function will most likely need to be changed -* as well. It's not ideal but I think the tradeoff in terms of -* neatness and speed is worth it. */ +/* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, +* however, it is not always compatible with an array of unsigned long +* in ebitmap_node. +* In addition, you should pay attention the following implementation +* assumes unsigned long has a width equal with or less than 64-bit. +*/ do {for (c_idx =0 ; c_idx <NETLBL_CATMAP_MAPCNT ; c_idx++) { -if (c_iter->bitmap[c_idx] ==0 ) +unsigned int delta; +u64 map = c_iter->bitmap[c_idx]; + +if (!map)continue ; - e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); -if (e_iter ==NULL ) - goto netlbl_import_failure; -if (emap_prev ==NULL ) - ebmap->node = e_iter; -else - emap_prev->next = e_iter; - emap_prev = e_iter; - - e_iter->startbit = c_iter->startbit + -NETLBL_CATMAP_MAPSIZE * c_idx; - e_iter->map = c_iter->bitmap[c_idx]; + c_pos = c_iter->startbit + + c_idx *NETLBL_CATMAP_MAPSIZE ; +if (!e_iter + || c_pos >= e_iter->startbit +EBITMAP_SIZE ) { + e_iter =kzalloc (sizeof (*e_iter),GFP_ATOMIC ); +if (!e_iter) + goto netlbl_import_failure; + e_iter->startbit + = c_pos - (c_pos %EBITMAP_SIZE ); +if (emap_prev ==NULL ) + ebmap->node = e_iter; +else + emap_prev->next = e_iter; + emap_prev = e_iter; + } + delta = c_pos - e_iter->startbit; + e_idx = delta /EBITMAP_UNIT_SIZE ; + e_sft = delta %EBITMAP_UNIT_SIZE ; +while (map) { + e_iter->maps[e_idx++] |= map & (-1UL ); + map >>=EBITMAP_UNIT_SIZE ; + } } c_iter = c_iter->next; }while (c_iter !=NULL );if (e_iter !=NULL ) - ebmap->highbit = e_iter->startbit +MAPSIZE ; + ebmap->highbit = e_iter->startbit +EBITMAP_SIZE ;else ebitmap_destroy (ebmap);@@ -186,6 +214,7 @@ netlbl_import_failure:int ebitmap_contains (struct ebitmap *e1,struct ebitmap *e2) {struct ebitmap_node *n1, *n2; +int i;if (e1->highbit < e2->highbit)return 0 ;@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) n1 = n1->next;continue ; } -if ((n1->map & n2->map) != n2->map) -return 0 ; +for (i =0 ; i <EBITMAP_UNIT_NUMS ; i++) { +if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) +return 0 ; + } n1 = n1->next; n2 = n2->next;@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) n = e->node;while (n && (n->startbit <= bit)) { -if ((n->startbit +MAPSIZE ) > bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) -return 1 ; -else -return 0 ; - } +if ((n->startbit +EBITMAP_SIZE ) > bit) +return ebitmap_node_get_bit (n, bit); n = n->next; }@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) prev =NULL ; n = e->node;while (n && n->startbit <= bit) { -if ((n->startbit +MAPSIZE ) > bit) { +if ((n->startbit +EBITMAP_SIZE ) > bit) {if (value) { - n->map |= (MAPBIT << (bit - n->startbit)); +ebitmap_node_set_bit (n, bit); }else { - n->map &= ~(MAPBIT << (bit - n->startbit)); -if (!n->map) { -/* drop this node from the bitmap */ - -if (!n->next) { -/* -* this was the highest map -* within the bitmap -*/ -if (prev) - e->highbit = prev->startbit +MAPSIZE ; -else - e->highbit =0 ; - } +unsigned int s; + +ebitmap_node_clr_bit (n, bit); + + s =find_first_bit (n->maps,EBITMAP_SIZE ); +if (s <EBITMAP_SIZE ) +return 0 ; + +/* drop this node from the bitmap */ +if (!n->next) { +/* +* this was the highest map +* within the bitmap +*/ if (prev) - prev->next = n->next; + e->highbit = prev->startbit + +EBITMAP_SIZE ;else - e->node = n->next; - -kfree (n); + e->highbit =0 ; } +if (prev) + prev->next = n->next; +else + e->node = n->next; +kfree (n); }return 0 ; }@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)if (!new)return -ENOMEM ; - new->startbit = bit & ~(MAPSIZE -1 ); - new->map = (MAPBIT << (bit - new->startbit)); + new->startbit = bit - (bit %EBITMAP_SIZE ); +ebitmap_node_set_bit (new, bit);if (!n)/* this node will be the highest map within the bitmap */ - e->highbit = new->startbit +MAPSIZE ; + e->highbit = new->startbit +EBITMAP_SIZE ;if (prev) { new->next = prev->next;@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)int ebitmap_read (struct ebitmap *e,void *fp) { -int rc; -struct ebitmap_node *n, *l; +struct ebitmap_node *n =NULL ; +u32 mapunit, count, startbit, index; +u64 map;__le32 buf[3 ]; -u32 mapsize, count, i; -__le64 map; +int rc, i;ebitmap_init (e);@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (rc <0 ) goto out; - mapsize =le32_to_cpu (buf[0 ]); + mapunit =le32_to_cpu (buf[0 ]); e->highbit =le32_to_cpu (buf[1 ]); count =le32_to_cpu (buf[2 ]); -if (mapsize !=MAPSIZE ) { +if (mapunit !=sizeof (u64) *8 ) {printk (KERN_ERR "security: ebitmap: map size %u does not " -"match my size %Zd (high bit was %d)\n" , mapsize, -MAPSIZE , e->highbit); +"match my size %Zd (high bit was %d)\n" , + mapunit,sizeof (u64) *8 , e->highbit); goto bad; } + +/* round up e->highbit */ + e->highbit +=EBITMAP_SIZE -1 ; + e->highbit -= (e->highbit %EBITMAP_SIZE ); +if (!e->highbit) { e->node =NULL ; goto ok; } -if (e->highbit & (MAPSIZE -1 )) { -printk (KERN_ERR "security: ebitmap: high bit (%d) is not a " -"multiple of the map size (%Zd)\n" , e->highbit,MAPSIZE ); - goto bad; - } - l =NULL ; +for (i =0 ; i < count; i++) { - rc =next_entry (buf, fp,sizeof (u32)); + rc =next_entry (&startbit, fp,sizeof (u32));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); goto bad; } - n =kzalloc (sizeof (*n),GFP_KERNEL ); -if (!n) { -printk (KERN_ERR "security: ebitmap: out of memory\n" ); - rc = -ENOMEM ; - goto bad; - } - - n->startbit =le32_to_cpu (buf[0 ]); + startbit =le32_to_cpu (startbit); -if (n->startbit & (MAPSIZE -1 )) { +if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map size (%Zd)\n" , - n->startbit,MAPSIZE ); - goto bad_free; +"not a multiple of the map unit size (%Zd)\n" , + startbit, mapunit); + goto bad; } -if (n->startbit > (e->highbit -MAPSIZE )) { +if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " "beyond the end of the bitmap (%Zd)\n" , - n->startbit, (e->highbit -MAPSIZE )); - goto bad_free; + startbit, (e->highbit - mapunit)); + goto bad; + } + +if (!n || startbit >= n->startbit +EBITMAP_SIZE ) { +struct ebitmap_node *tmp; + tmp =kzalloc (sizeof (*tmp),GFP_KERNEL ); +if (!tmp) { +printk (KERN_ERR +"security: ebitmap: out of memory\n" ); + rc = -ENOMEM ; + goto bad; + } +/* round down */ + tmp->startbit = startbit - (startbit %EBITMAP_SIZE ); +if (n) { + n->next = tmp; + }else { + e->node = tmp; + } + n = tmp; + }else if (startbit <= n->startbit) { +printk (KERN_ERR "security: ebitmap: start bit %d" +" comes after start bit %d\n" , + startbit, n->startbit); + goto bad; } + rc =next_entry (&map, fp,sizeof (u64));if (rc <0 ) {printk (KERN_ERR "security: ebitmap: truncated map\n" ); - goto bad_free; + goto bad; } - n->map =le64_to_cpu (map); + map =le64_to_cpu (map); -if (!n->map) { -printk (KERN_ERR "security: ebitmap: null map in " -"ebitmap (startbit %d)\n" , n->startbit); - goto bad_free; + index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +while (map) { + n->maps[index] = map & (-1UL ); + map = map >>EBITMAP_UNIT_SIZE ; + index++; } -if (l) { -if (n->startbit <= l->startbit) { -printk (KERN_ERR "security: ebitmap: start " -"bit %d comes after start bit %d\n" , - n->startbit, l->startbit); - goto bad_free; - } - l->next = n; - }else - e->node = n; - - l = n; } - ok: rc =0 ; out:return rc; -bad_free: -kfree (n); bad:if (!rc) rc = -EINVAL ;security/selinux/ss/ebitmap.h +66
-21@@ -16,14 +16,16 @@#include <net/netlabel.h> -#define MAPTYPE u64/* portion of bitmap in each node */ -#define MAPSIZE (sizeof(MAPTYPE) * 8)/* number of bits in node bitmap */ -#define MAPBIT 1ULL/* a bit in the node bitmap */ +#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \ + / sizeof(unsigned long)) +#define EBITMAP_UNIT_SIZE BITS_PER_LONG +#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) +#define EBITMAP_BIT 1ULLstruct ebitmap_node { -u32 startbit;/* starting position in the total bitmap */ -MAPTYPE map;/* this node's portion of the bitmap */ struct ebitmap_node *next; +unsigned long maps[EBITMAP_UNIT_NUMS ]; +u32 startbit; };struct ebitmap {@@ -34,11 +36,17 @@ struct ebitmap {#define ebitmap_length (e) ((e)->highbit)#define ebitmap_startbit (e) ((e)->node ? (e)->node->startbit : 0) -static inline unsigned int ebitmap_start (struct ebitmap *e, -struct ebitmap_node **n) +static inline unsigned int ebitmap_start_positive (struct ebitmap *e, +struct ebitmap_node **n) { - *n = e->node; -return ebitmap_startbit (e); +unsigned int ofs; + +for (*n = e->node; *n; *n = (*n)->next) { + ofs =find_first_bit ((*n)->maps,EBITMAP_SIZE ); +if (ofs <EBITMAP_SIZE ) +return (*n)->startbit + ofs; + } +return ebitmap_length (e); }static inline void ebitmap_init (struct ebitmap *e)@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)memset (e,0 ,sizeof (*e)); } -static inline unsigned int ebitmap_next (struct ebitmap_node **n, -unsigned int bit) +static inline unsigned int ebitmap_next_positive (struct ebitmap *e, +struct ebitmap_node **n, +unsigned int bit) { -if ((bit == ((*n)->startbit +MAPSIZE -1 )) && - (*n)->next) { - *n = (*n)->next; -return (*n)->startbit; - } +unsigned int ofs; + + ofs =find_next_bit ((*n)->maps,EBITMAP_SIZE , bit - (*n)->startbit +1 ); +if (ofs <EBITMAP_SIZE ) +return ofs + (*n)->startbit; -return (bit+1 ); +for (*n = (*n)->next; *n; *n = (*n)->next) { + ofs =find_first_bit ((*n)->maps,EBITMAP_SIZE ); +if (ofs <EBITMAP_SIZE ) +return ofs + (*n)->startbit; + } +return ebitmap_length (e); } -static inline int ebitmap_node_get_bit (struct ebitmap_node * n, +#define EBITMAP_NODE_INDEX (node, bit) \ + (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE) +#define EBITMAP_NODE_OFFSET (node, bit) \ + (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE) + +static inline int ebitmap_node_get_bit (struct ebitmap_node *n,unsigned int bit) { -if (n->map & (MAPBIT << (bit - n->startbit))) +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); +if ((n->maps[index] & (EBITMAP_BIT << ofs)))return 1 ;return 0 ; } -#define ebitmap_for_each_bit (e, n, bit) \ - for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ +static inline void ebitmap_node_set_bit (struct ebitmap_node *n, +unsigned int bit) +{ +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); + n->maps[index] |= (EBITMAP_BIT << ofs); +} + +static inline void ebitmap_node_clr_bit (struct ebitmap_node *n, +unsigned int bit) +{ +unsigned int index =EBITMAP_NODE_INDEX (n, bit); +unsigned int ofs =EBITMAP_NODE_OFFSET (n, bit); + +BUG_ON (index >=EBITMAP_UNIT_NUMS ); + n->maps[index] &= ~(EBITMAP_BIT << ofs); +} + +#define ebitmap_for_each_positive_bit (e, n, bit) \ + for (bit = ebitmap_start_positive(e, &n); \ + bit < ebitmap_length(e); \ + bit = ebitmap_next_positive(e, &n, bit)) \int ebitmap_cmp (struct ebitmap *e1,struct ebitmap *e2);int ebitmap_cpy (struct ebitmap *dst,struct ebitmap *src);security/selinux/ss/mls.c +75
-81@@ -34,7 +34,9 @@*/ int mls_compute_context_len (struct context * context) { -int i, l, len, range; +int i, l, len, head, prev; +char *nm; +struct ebitmap *e;struct ebitmap_node *node;if (!selinux_mls_enabled)@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context) len =1 ;/* for the beginning ":" */ for (l =0 ; l <2 ; l++) { - range =0 ; - len +=strlen (policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); - -ebitmap_for_each_bit (&context->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (range) { - range++; -continue ; - } +int index_sens = context->range.level[l].sens; + len +=strlen (policydb.p_sens_val_to_name[index_sens -1 ]); - len +=strlen (policydb.p_cat_val_to_name[i]) +1 ; - range++; - }else { -if (range >1 ) - len +=strlen (policydb.p_cat_val_to_name[i -1 ]) +1 ; - range =0 ; +/* categories */ + head =-2 ; + prev =-2 ; + e = &context->range.level[l].cat; +ebitmap_for_each_positive_bit (e, node, i) { +if (i - prev >1 ) { +/* one or more negative bits are skipped */ +if (head != prev) { + nm = policydb.p_cat_val_to_name[prev]; + len +=strlen (nm) +1 ; + } + nm = policydb.p_cat_val_to_name[i]; + len +=strlen (nm) +1 ; + head = i; } + prev = i; + } +if (prev != head) { + nm = policydb.p_cat_val_to_name[prev]; + len +=strlen (nm) +1 ; } -/* Handle case where last category is the end of range */ -if (range >1 ) - len +=strlen (policydb.p_cat_val_to_name[i -1 ]) +1 ; -if (l ==0 ) {if (mls_level_eq (&context->range.level[0 ], - &context->range.level[1 ])) + &context->range.level[1 ]))break ;else len++;@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)void mls_sid_to_context (struct context *context,char **scontext) { -char *scontextp; -int i, l, range, wrote_sep; +char *scontextp, *nm; +int i, l, head, prev; +struct ebitmap *e;struct ebitmap_node *node;if (!selinux_mls_enabled)@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context, scontextp++;for (l =0 ; l <2 ; l++) { - range =0 ; - wrote_sep =0 ;strcpy (scontextp, policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); - scontextp +=strlen (policydb.p_sens_val_to_name[context->range.level[l].sens -1 ]); + scontextp +=strlen (scontextp);/* categories */ -ebitmap_for_each_bit (&context->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (range) { - range++; -continue ; - } - -if (!wrote_sep) { - *scontextp++ =':' ; - wrote_sep =1 ; - }else - *scontextp++ =',' ; -strcpy (scontextp, policydb.p_cat_val_to_name[i]); - scontextp +=strlen (policydb.p_cat_val_to_name[i]); - range++; - }else { -if (range >1 ) { -if (range >2 ) + head =-2 ; + prev =-2 ; + e = &context->range.level[l].cat; +ebitmap_for_each_positive_bit (e, node, i) { +if (i - prev >1 ) { +/* one or more negative bits are skipped */ +if (prev != head) { +if (prev - head >1 ) *scontextp++ ='.' ;else *scontextp++ =',' ; - -strcpy (scontextp, policydb.p_cat_val_to_name[i -1 ]); - scontextp +=strlen (policydb.p_cat_val_to_name[i -1 ]); + nm = policydb.p_cat_val_to_name[prev]; +strcpy (scontextp, nm); + scontextp +=strlen (nm); } - range =0 ; +if (prev <0 ) + *scontextp++ =':' ; +else + *scontextp++ =',' ; + nm = policydb.p_cat_val_to_name[i]; +strcpy (scontextp, nm); + scontextp +=strlen (nm); + head = i; } + prev = i; } -/* Handle case where last category is the end of range */ -if (range >1 ) { -if (range >2 ) +if (prev != head) { +if (prev - head >1 ) *scontextp++ ='.' ;else *scontextp++ =',' ; - -strcpy (scontextp, policydb.p_cat_val_to_name[i -1 ]); - scontextp +=strlen (policydb.p_cat_val_to_name[i -1 ]); + nm = policydb.p_cat_val_to_name[prev]; +strcpy (scontextp, nm); + scontextp +=strlen (nm); }if (l ==0 ) {if (mls_level_eq (&context->range.level[0 ], &context->range.level[1 ]))break ; -else { - *scontextp ='-' ; - scontextp++; - } +else + *scontextp++ ='-' ; } }@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)if (!levdatum)return 0 ; -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -if (i > p->p_cats.nprim) -return 0 ; -if (!ebitmap_get_bit (&levdatum->level->cat, i)) -/* -* Category may not be associated with -* sensitivity in low level. -*/ -return 0 ; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +if (i > p->p_cats.nprim) +return 0 ; +if (!ebitmap_get_bit (&levdatum->level->cat, i)) +/* +* Category may not be associated with +* sensitivity in low level. +*/ +return 0 ; } }@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp, c->range.level[l].sens = levdatum->level->sens;ebitmap_init (&bitmap); -ebitmap_for_each_bit (&c->range.level[l].cat, node, i) { -if (ebitmap_node_get_bit (node, i)) { -int rc; - - catdatum =hashtab_search (newp->p_cats.table, - oldp->p_cat_val_to_name[i]); -if (!catdatum) -return -EINVAL ; - rc =ebitmap_set_bit (&bitmap, catdatum->value -1 ,1 ); -if (rc) -return rc; - } +ebitmap_for_each_positive_bit (&c->range.level[l].cat, node, i) { +int rc; + + catdatum =hashtab_search (newp->p_cats.table, + oldp->p_cat_val_to_name[i]); +if (!catdatum) +return -EINVAL ; + rc =ebitmap_set_bit (&bitmap, catdatum->value -1 ,1 ); +if (rc) +return rc; }ebitmap_destroy (&c->range.level[l].cat); c->range.level[l].cat = bitmap;security/selinux/ss/services.c +4
-13@@ -329,12 +329,8 @@ static int context_struct_compute_av(struct context *scontext, avkey.specified =AVTAB_AV ; sattr = &policydb.type_attr_map[scontext->type -1 ]; tattr = &policydb.type_attr_map[tcontext->type -1 ]; -ebitmap_for_each_bit (sattr, snode, i) { -if (!ebitmap_node_get_bit (snode, i)) -continue ; -ebitmap_for_each_bit (tattr, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (sattr, snode, i) { +ebitmap_for_each_positive_bit (tattr, tnode, j) { avkey.source_type = i +1 ; avkey.target_type = j +1 ; for (node = avtab_search_node(&policydb.te_avtab, &avkey);@@ -1621,14 +1617,10 @@ int security_get_user_sids(u32 fromsid, goto out_unlock; } -ebitmap_for_each_bit (&user->roles, rnode, i) { -if (!ebitmap_node_get_bit (rnode, i)) -continue ; +ebitmap_for_each_positive_bit (&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; usercon.role = i+1 ; -ebitmap_for_each_bit (&role->types, tnode, j) { -if (!ebitmap_node_get_bit (tnode, j)) -continue ; +ebitmap_for_each_positive_bit (&role->types, tnode, j) { usercon.type = j+1 ;if (mls_setup_user_range (fromcon, user, &usercon)) --This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
In reply to KaiGai KoheiQuoted 14 lines · KaiGai Kohei
Quoted 4 lines · Stephen Smalley
Quoted 3 lines · KaiGai Kohei
Quoted 2 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.Seems to be damaged, or at least doesn't apply for me. What is it relative to?
Quoted 6 lines
I generated the patch against to the latest of James's git tree But it seems to me that all tab chatacters are translated into four white spaces, when I copied and pasted the patch. I'm sorry, it was my misoperation.
Can you receive it with tab kept in this time?
Yes, but there are compiler warnings on 64-bit.
Please test it on a 64-bit machine.
$ make -j3 SUBDIRS=security CC security/selinux/ss/ebitmap.o CC security/selinux/ss/sidtab.o CC security/selinux/ss/avtab.o security/selinux/ss/ebitmap.c: In function ‘ebitmap_netlbl_import’: security/selinux/ss/ebitmap.c:196: warning: right shift count >= width of type security/selinux/ss/ebitmap.c: In function ‘ebitmap_read’: security/selinux/ss/ebitmap.c:393: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’ security/selinux/ss/ebitmap.c:399: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’ security/selinux/ss/ebitmap.c:437: warning: right shift count >= width of type
Signature · 2 lines
James Morris <[email protected]>
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 23 lines · James Morris
Quoted 8 lines · KaiGai Kohei
Quoted 7 lines · Stephen Smalley
Quoted 6 lines · KaiGai Kohei
Quoted 3 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.Quoted 8 lines
Quoted 2 lines
Seems to be damaged, or at least doesn't apply for me. What is it relative to?
I generated the patch against to the latest of James's git tree But it seems to me that all tab chatacters are translated into four white spaces, when I copied and pasted the patch. I'm sorry, it was my misoperation.
Can you receive it with tab kept in this time?
Yes, but there are compiler warnings on 64-bit.
Please test it on a 64-bit machine.
Quoted 10 lines
$ make -j3 SUBDIRS=security CC security/selinux/ss/ebitmap.o CC security/selinux/ss/sidtab.o CC security/selinux/ss/avtab.o security/selinux/ss/ebitmap.c: In function ‘ebitmap_netlbl_import’: security/selinux/ss/ebitmap.c:196: warning: right shift count >= width of type security/selinux/ss/ebitmap.c: In function ‘ebitmap_read’: security/selinux/ss/ebitmap.c:393: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’ security/selinux/ss/ebitmap.c:399: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’ security/selinux/ss/ebitmap.c:437: warning: right shift count >= width of type
The attached patch kills these warnings.
While killing them, I faced to a serious bug.
At first, I expected the following while { ... } block is never looped multiple time in 64-bit architecture.
--------
+#if EBITMAP_UNIT_SIZE == 64
+ n->maps[index] = map;
+#else
while (map) {
n->maps[index] = map & (-1UL); map = map >> EBITMAP_UNIT_SIZE; index++;
}
+#endif
--------
However, I might misunderstand about the works of shift operations. When we tries to shift a variable with the width of it, this operation does not give us any effect.
See the following small code.
[kaigai@masu ~]$ cat hoge.c
#include <stdio.h>
int main(int argc, char *argv[]) {
unsigned long code = -1UL;
printf("code = %016lx\n", code);
printf("code >> 16 = %016lx\n", code >> 16);
printf("code >> 63 = %016lx\n", code >> 63);
printf("code >> 64 = %016lx\n", code >> 64);
printf("code >> 65 = %016lx\n", code >> 65);
return 0;
}[kaigai@masu ~]$ env LANG=C gcc hoge.c hoge.c: In function 'main':
hoge.c:9: warning: right shift count >= width of type hoge.c:10: warning: right shift count >= width of type [kaigai@masu ~]$ ./a.out
code = ffffffffffffffff
code >> 16 = 0000ffffffffffff
code >> 63 = 0000000000000001
code >> 64 = ffffffffffffffff
code >> 65 = 7fffffffffffffff
[kaigai@masu ~]$ uname -mx86_64
I was suprised at. :-)
It is the reason why I put #if block to separate 64bit/32bit cases.
Do you have any idea to write it more simply?
----------------------------------------
[PATCH] kills warnings in Improve SELinux performance when AVC misses
This patch kills ugly warnings when the "Improve SELinux performance when ACV misses" patch.
--- security/selinux/ss/ebitmap.c | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-)
security/selinux/ss/ebitmap.c +10 -2
@@ -191,10 +191,14 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, delta = c_pos - e_iter->startbit; e_idx = delta /EBITMAP_UNIT_SIZE ; e_sft = delta %EBITMAP_UNIT_SIZE ; +#if EBITMAP_UNIT_SIZE ==64 + e_iter->maps[e_idx] |= map; +#else while (map) { e_iter->maps[e_idx++] |= map & (-1UL ); map >>=EBITMAP_UNIT_SIZE ; } +#endif } c_iter = c_iter->next; }while (c_iter !=NULL );
@@ -389,13 +393,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map unit size (%Zd)\n" , +"not a multiple of the map unit size (%u)\n" , startbit, mapunit); goto bad; }if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"beyond the end of the bitmap (%Zd)\n" , +"beyond the end of the bitmap (%u)\n" , startbit, (e->highbit - mapunit)); goto bad; }
@@ -432,11 +436,15 @@ int ebitmap_read(struct ebitmap *e, void *fp) map =le64_to_cpu (map); index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +#if EBITMAP_UNIT_SIZE ==64 + n->maps[index] = map; +#else while (map) { n->maps[index] = map & (-1UL ); map = map >>EBITMAP_UNIT_SIZE ; index++; } +#endif } ok: rc =0 ;
Signature · 7 lines
KaiGai Kohei <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 88 lines · KaiGai Kohei
Quoted 25 lines · James Morris
Quoted 10 lines · KaiGai Kohei
Quoted 9 lines · Stephen Smalley
Quoted 8 lines · KaiGai Kohei
Quoted 5 lines · James Morris
Quoted 2 lines
++ struct
ebitmap_node*_n;
++ _n =kzalloc(sizeof(*_n), GFP_KERNEL);Leading underscores are usually used to indicate that core code is not supposed to use the symbol. Please change it to not have a leading underscore. 'tmp' or 'n2' is probably ok.
OK, I replaced all of '_n' by 'tmp'.
Rest of the part in the following patch is same as the previous one.Quoted 8 lines
Quoted 2 lines
Seems to be damaged, or at least doesn't apply for me. What is it relative to?
I generated the patch against to the latest of James's git tree But it seems to me that all tab chatacters are translated into four white spaces, when I copied and pasted the patch. I'm sorry, it was my misoperation.
Can you receive it with tab kept in this time?
Yes, but there are compiler warnings on 64-bit.
Please test it on a 64-bit machine.
Quoted 10 lines
$ make -j3 SUBDIRS=security CC security/selinux/ss/ebitmap.o CC security/selinux/ss/sidtab.o CC security/selinux/ss/avtab.o security/selinux/ss/ebitmap.c: In function ‘ebitmap_netlbl_import’: security/selinux/ss/ebitmap.c:196: warning: right shift count >= width of type security/selinux/ss/ebitmap.c: In function ‘ebitmap_read’: security/selinux/ss/ebitmap.c:393: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’ security/selinux/ss/ebitmap.c:399: warning: format ‘%Zd’ expects type ‘signed size_t’, but argument 3 has type ‘u32’ security/selinux/ss/ebitmap.c:437: warning: right shift count >= width of typeThe attached patch kills these warnings.
While killing them, I faced to a serious bug.
At first, I expected the following while { ... } block is never looped multiple time in 64-bit architecture.--------
security/selinux/ss/ebitmap.c +4
-1+#if EBITMAP_UNIT_SIZE ==64 + n->maps[index] = map; +#else while (map) { n->maps[index] = map & (-1UL ); map = map >>EBITMAP_UNIT_SIZE ; index++; } +#endif --------However, I might misunderstand about the works of shift operations. When we tries to shift a variable with the width of it, this operation does not give us any effect.
See the following small code.
[kaigai@masu ~]$ cat
hoge.c
#include <stdio.h>int main(int argc, char *argv[]) { unsigned long code = -1UL; printf("code = %016lx\n", code); printf("code >> 16 = %016lx\n", code >> 16); printf("code >> 63 = %016lx\n", code >> 63); printf("code >> 64 = %016lx\n", code >> 64); printf("code >> 65 = %016lx\n", code >> 65); return 0; }[kaigai@masu ~]$ env LANG=C gcc
hoge.choge.c: In function 'main':
hoge.c:9: warning: right shift count >= width of type hoge.c:10: warning: right shift count >= width of type [kaigai@masu ~]$ ./a.out
code = ffffffffffffffff
code >> 16 =0000ffffffffffff
code >> 63 = 0000000000000001
code >> 64 = ffffffffffffffff
code >> 65 =7fffffffffffffff
[kaigai@masu ~]$ uname -mx86_64
Quoted 1 line
I was suprised at. :-)
Me too. But see:
http://gcc.gnu.org/ml/gcc/2004-11/msg01133.html
http://marc.info/?t=118688311400003&r=1&w=2
Quoted 67 lines
It is the reason why I put #if block to separate 64bit/32bit cases.
Do you have any idea to write it more simply?
----------------------------------------
[PATCH] kills warnings in Improve SELinux performance when AVC missesThis patch kills ugly warnings when the "Improve SELinux performance when ACV misses" patch.
Signed-off-by KaiGai Kohei <[email protected]>--- security/selinux/ss/ebitmap.c | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-)security/selinux/ss/ebitmap.c +10
-2@@ -191,10 +191,14 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, delta = c_pos - e_iter->startbit; e_idx = delta /EBITMAP_UNIT_SIZE ; e_sft = delta %EBITMAP_UNIT_SIZE ; +#if EBITMAP_UNIT_SIZE ==64 + e_iter->maps[e_idx] |= map; +#else while (map) { e_iter->maps[e_idx++] |= map & (-1UL ); map >>=EBITMAP_UNIT_SIZE ; } +#endif } c_iter = c_iter->next; }while (c_iter !=NULL );@@ -389,13 +393,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map unit size (%Zd)\n" , +"not a multiple of the map unit size (%u)\n" , startbit, mapunit); goto bad; }if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"beyond the end of the bitmap (%Zd)\n" , +"beyond the end of the bitmap (%u)\n" , startbit, (e->highbit - mapunit)); goto bad; }@@ -432,11 +436,15 @@ int ebitmap_read(struct ebitmap *e, void *fp) map =le64_to_cpu (map); index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ; +#if EBITMAP_UNIT_SIZE ==64 + n->maps[index] = map; +#else while (map) { n->maps[index] = map & (-1UL ); map = map >>EBITMAP_UNIT_SIZE ; index++; } +#endif } ok: rc =0 ;
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 11 lines
Review
Quoted 11 lines
--------
(quoted diff) +4
-1+#if EBITMAP_UNIT_SIZE == 64 + n->maps[index] = map; +#else while (map) { n->maps[index] = map & (-1UL); map = map >> EBITMAP_UNIT_SIZE; index++; } +#endif --------
- snip -
Quoted 9 lines
Quoted 9 lines
[kaigai@masu ~]$ ./a.out
code = ffffffffffffffff
code >> 16 =0000ffffffffffff
code >> 63 = 0000000000000001
code >> 64 = ffffffffffffffff
code >> 65 =7fffffffffffffff
[kaigai@masu ~]$ uname -mx86_64
Quoted 5 lines
Quoted 1 line
I was suprised at. :-)
Me too. But see:
http://gcc.gnu.org/ml/gcc/2004-11/msg01133.html
http://marc.info/?t=118688311400003&r=1&w=2
#if ... #endif block was removed in the previous patch.
I added a macro that shifts a variable by the width of unsigned long, defined as follows:
#define EBITMAP_SHIFT_UNIT_SIZE(x) \ (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
[PATCH] kills warnings in Improve SELinux performance when AVC misses
This patch kills ugly warnings when the "Improve SELinux performance when ACV misses" patch.
--- security/selinux/ss/ebitmap.c | 11 +++++------ security/selinux/ss/ebitmap.h | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-)
security/selinux/ss/ebitmap.c +5 -6
@@ -193,7 +193,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, e_sft = delta %EBITMAP_UNIT_SIZE ;while (map) { e_iter->maps[e_idx++] |= map & (-1UL ); - map >>=EBITMAP_UNIT_SIZE ; + map =EBITMAP_SHIFT_UNIT_SIZE (map); } } c_iter = c_iter->next;
@@ -389,13 +389,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map unit size (%Zd)\n" , +"not a multiple of the map unit size (%u)\n" , startbit, mapunit); goto bad; }if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"beyond the end of the bitmap (%Zd)\n" , +"beyond the end of the bitmap (%u)\n" , startbit, (e->highbit - mapunit)); goto bad; }
@@ -433,9 +433,8 @@ int ebitmap_read(struct ebitmap *e, void *fp) index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ;while (map) { - n->maps[index] = map & (-1UL ); - map = map >>EBITMAP_UNIT_SIZE ; - index++; + n->maps[index++] = map & (-1UL ); + map =EBITMAP_SHIFT_UNIT_SIZE (map); } } ok:
security/selinux/ss/ebitmap.h +2 -0
@@ -21,6 +21,8 @@#define EBITMAP_UNIT_SIZE BITS_PER_LONG#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)#define EBITMAP_BIT 1ULL +#define EBITMAP_SHIFT_UNIT_SIZE (x) \ + (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)struct ebitmap_node {struct ebitmap_node *next;
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
Quoted 6 lines
Quoted 5 lines
Quoted 1 line
I was suprised at. :-)
Me too. But see:
http://gcc.gnu.org/ml/gcc/2004-11/msg01133.html
http://marc.info/?t=118688311400003&r=1&w=2
Quoted 8 lines
#if ... #endif block was removed in the previous patch.
I added a macro that shifts a variable by the width of unsigned long, defined as follows:#define EBITMAP_SHIFT_UNIT_SIZE(x) \ (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)[PATCH] kills warnings in Improve SELinux performance when AVC misses
Sorry, tab character were polluted again.
It seems to me that Thunderbird replace tab character into four white spaces when I use "Content-Type: text/plain; charset=UTF-8".
I resend this one as follows.
[PATCH] kills warnings in Improve SELinux performance when AVC misses
This patch kills ugly warnings when the "Improve SELinux performance when ACV misses" patch.
--- security/selinux/ss/ebitmap.c | 11 +++++------ security/selinux/ss/ebitmap.h | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-)
security/selinux/ss/ebitmap.c +5 -6
@@ -193,7 +193,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, e_sft = delta %EBITMAP_UNIT_SIZE ;while (map) { e_iter->maps[e_idx++] |= map & (-1UL ); - map >>=EBITMAP_UNIT_SIZE ; + map =EBITMAP_SHIFT_UNIT_SIZE (map); } } c_iter = c_iter->next;
@@ -389,13 +389,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)if (startbit & (mapunit -1 )) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"not a multiple of the map unit size (%Zd)\n" , +"not a multiple of the map unit size (%u)\n" , startbit, mapunit); goto bad; }if (startbit > e->highbit - mapunit) {printk (KERN_ERR "security: ebitmap start bit (%d) is " -"beyond the end of the bitmap (%Zd)\n" , +"beyond the end of the bitmap (%u)\n" , startbit, (e->highbit - mapunit)); goto bad; }
@@ -433,9 +433,8 @@ int ebitmap_read(struct ebitmap *e, void *fp) index = (startbit - n->startbit) /EBITMAP_UNIT_SIZE ;while (map) { - n->maps[index] = map & (-1UL ); - map = map >>EBITMAP_UNIT_SIZE ; - index++; + n->maps[index++] = map & (-1UL ); + map =EBITMAP_SHIFT_UNIT_SIZE (map); } } ok:
security/selinux/ss/ebitmap.h +2 -0
@@ -21,6 +21,8 @@#define EBITMAP_UNIT_SIZE BITS_PER_LONG#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)#define EBITMAP_BIT 1ULL +#define EBITMAP_SHIFT_UNIT_SIZE (x) \ + (((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)struct ebitmap_node {struct ebitmap_node *next;
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH] Improve SELinux performance when AVC misses.
All applied togit://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6.git#for-akpm
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 3 lines · Yuichi Nakamura
Hi.
I would like to propose patch that reduce memory usage of avtab again.
This looks good, although there are some coding style and other issues which need to be fixed. Also see Documentation/SubmittingPatches and Documentation/CodingStyle in the kernel tree.
Quoted 4 lines
Next is a patch.
Signed-off-by Yuichi Nakamura <[email protected]>----
Needs to be 3 --- otherwise scripts will break.
Quoted 5 lines
avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------------- avtab.h | 13 +++++++----- conditional.c | 6 +++++ policydb.c | 9 ++------ 4 files changed, 64 insertions(+), 25 deletions(-)
diffstat -p1
Quoted 2 lines
diff -ur
security/selinux.notuning/ss/avtab.csecurity/selinux/ss/avtab.c
diff -purN
selinux/ss/avtab.c line 64
Quoted 1 line
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +1
-0+ hvalue =AVTAB_HASH (key,h->mask);
Add a space after the comma.
Also, AVTAB_HASH should be converted to a static inline.
selinux/ss/avtab.c line 259
Quoted 1 line
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +1
-0+while (work) {
Space after while.
selinux/ss/avtab.c line 265
Quoted 3 lines
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +3
-0+if (shift >2 ) { + shift = shift -2 ; + }
No need for braces for a one-line statement.
selinux/ss/avtab.c line 269
Quoted 4 lines
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +4
-0+ nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) { + nslot =MAX_AVTAB_SIZE ; + }
Ditto.
selinux/ss/avtab.c line 272
Quoted 2 lines
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +1
-1- h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kmalloc (sizeof (*(h->htable)) * nslot,GFP_KERNEL );
Use kcalloc(), then consider the effect of the memory zeroing & how much further code can be removed.
selinux/ss/avtab.c line 280
Quoted 1 line
selinux/ss/avtab.c renamed from selinux.notuning/ss/avtab.c +1
-0+printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n" , h->nslot, nrules);
This line is too long.
selinux/ss/conditional.c line 461
Quoted 3 lines
selinux/ss/conditional.c renamed from selinux.notuning/ss/conditional.c +3
-0+ rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) { + rc = -ENOMEM ;
Why are you resetting rc to the same value?
Review
Quoted 2 lines
(quoted diff) +1
-1- goto out_free_symtab; + goto out_free_symtab;
Looks like you added a trailing tab.
- James
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 9 lines · On Tue, 21 Aug 2007 07:00:56 -0700 (PDT) James Morris wrote:
Quoted 3 lines · Yuichi Nakamura
Hi.
I would like to propose patch that reduce memory usage of avtab again.
This looks good, although there are some coding style and other issues which need to be fixed. Also see
Documentation/SubmittingPatchesandDocumentation/CodingStylein the kernel tree.
Thanks for review !
Quoted 6 lines
Quoted 4 lines
Next is a patch.
Signed-off-by Yuichi Nakamura <[email protected]>----
Needs to be 3 --- otherwise scripts will break.
Fixed.
Quoted 8 lines
Quoted 6 lines
avtab.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------------- avtab.h | 13 +++++++----- conditional.c | 6 +++++ policydb.c | 9 ++------ 4 files changed, 64 insertions(+), 25 deletions(-)diffstat -p1
Fixed.
Quoted 5 lines
Quoted 3 lines
diff -ur
security/selinux.notuning/ss/avtab.csecurity/selinux/ss/avtab.cdiff -purN
Fixed.
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ hvalue = AVTAB_HASH(key,h->mask);Add a space after the comma.
Fixed.
Quoted 7 lines
Also,
AVTAB_HASHshould be converted to a static inline.Review
Quoted 1 line
(quoted diff) +1
-0+ while(work) {Space after while.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ if (shift > 2) { + shift = shift - 2; + }No need for braces for a one-line statement.
Fixed
Quoted 7 lines
Review
Quoted 5 lines
(quoted diff) +4
-0+ nslot = 1 << shift; + if (nslot > MAX_AVTAB_SIZE) { + nslot = MAX_AVTAB_SIZE; + }Ditto.
Fixed.
Quoted 6 lines
Review
Quoted 3 lines
(quoted diff) +1
-1- h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE); + h->htable = kmalloc(sizeof(*(h->htable)) * nslot, GFP_KERNEL);Use
kcalloc(), then consider the effect of the memory zeroing & how much further code can be removed.
Fixed.
And removed loop that clears h->htable.
Quoted 3 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. Num of rules:%d\n", h->nslot, nrules);This line is too long.
Fixed.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel); + if (rc) { + rc = -ENOMEM;Why are you resetting rc to the same value?
Removed rc=-ENOMEM.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +1
-1- goto out_free_symtab; + goto out_free_symtab;Looks like you added a trailing tab.
Fixed.
Quoted 7 lines
- James
Signature · 2 lines
James Morris <[email protected]>
And I've fixed avtab_hash_eval(struct avtab *h, char *tag), to print out sum of chain length^2 to calculate the standard deviation. Following is an updated patch.
--- security/selinux/ss/avtab.c | 71 ++++++++++++++++++++++++++++---------- security/selinux/ss/avtab.h | 16 +++++--- security/selinux/ss/conditional.c | 5 ++ security/selinux/ss/policydb.c | 7 +-- 4 files changed, 72 insertions(+), 27 deletions(-)
security/selinux/ss/avtab.c +54 -17
@@ -12,21 +12,23 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> #include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ +#define AVTAB_HASH (keyp, mask) \ ((keyp->target_class + \ (keyp->target_type << 2) + \ (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) + mask)static struct kmem_cache *avtab_node_cachep;
@@ -62,7 +64,7 @@ static int avtab_insert(struct avtab *h,if (!h)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -102,7 +104,7 @@ avtab_insert_nonunique(struct avtab * h,if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -135,7 +137,7 @@ struct avtab_datum *avtab_search(structif (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -170,7 +172,7 @@ avtab_search_node(struct avtab *h, strucif (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =AVTAB_HASH (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -228,7 +230,7 @@ void avtab_destroy(struct avtab *h)if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;
@@ -237,32 +239,58 @@ void avtab_destroy(struct avtab *h) } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { -int i; + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); +int avtab_alloc (struct avtab *h,int nrules) +{ +u16 mask; +u32 shift =0 ; +u32 work = nrules; +u32 nslot; + +while (work) { + work = work>>1 ; + shift++; + } +if (shift >2 ) + shift = shift -2 ; + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) + nslot =MAX_AVTAB_SIZE ; + mask = nslot -1 ; + + h->htable =kcalloc (nslot,sizeof (*(h->htable)),GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) - h->htable[i] =NULL ; h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated." +"Num of rules:%d\n" , h->nslot, nrules);return 0 ; }void avtab_hash_eval (struct avtab *h,char *tag) {int i, chain_len, slots_used, max_chain_len; +unsigned long long chain2_len_sum;struct avtab_node *cur; slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { + chain2_len_sum =0 ; +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;
@@ -274,12 +302,14 @@ void avtab_hash_eval(struct avtab *h, chif (chain_len > max_chain_len) max_chain_len = chain_len; + chain2_len_sum += chain_len * chain_len; } }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , - max_chain_len); +"chain length %d sum of chain length^2 %Lu\n" , + tag, h->nel, slots_used, h->nslot, max_chain_len, + chain2_len_sum); }static uint16_t spec_order[] = {
@@ -419,6 +449,13 @@ int avtab_read(struct avtab *a, void *fp rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) { + rc = -ENOMEM ; + goto bad; + } +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {
security/selinux/ss/avtab.h +11 -5
@@ -16,6 +16,9 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #ifndef _SS_AVTAB_H_#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,int );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nexvoid avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */
security/selinux/ss/conditional.c +5 -0
@@ -456,6 +456,11 @@ int cond_read_list(struct policydb *p, v len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) { + goto err; + } +for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );if (!node)
security/selinux/ss/policydb.c +2 -5
@@ -176,18 +176,15 @@ static int policydb_init(struct policydb rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 9 lines · Yuichi Nakamura
Quoted 6 lines · On Tue, 21 Aug 2007 07:00:56 -0700 (PDT) James Morris wrote:
Quoted 3 lines · Yuichi Nakamura
Hi.
I would like to propose patch that reduce memory usage of avtab again.
This looks good, although there are some coding style and other issues which need to be fixed. Also see
Documentation/SubmittingPatchesandDocumentation/CodingStylein the kernel tree.Thanks for review !
FYI.
These documents are also translated into Japanese language.
http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/SubmittingPatches.html
http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/CodingStyle.html
Signature · 7 lines
OSS Platform Development Division, NEC KaiGai Kohei <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
On Wed, 22 Aug 2007, Yuichi Nakamura wrote:
Just a couple more nits...
Quoted 6 lines
+#define
AVTAB_HASH(keyp, mask)\
((keyp->target_class+ \
(keyp->target_type<< 2) + \
(keyp->source_type<< 9)) & \
-AVTAB_HASH_MASK)
+ mask)
Can you make this a static inline ?
security/selinux/ss/conditional.c int cond_read_list(struct policydb *p, v · line 462
Quoted 3 lines
security/selinux/ss/conditional.c +3
-0+if (rc) { + goto err; + }
Don't need these braces.
- James
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 5 lines · On Wed, 22 Aug 2007 06:44:34 -0700 (PDT) James Morris wrote:
On Wed, 22 Aug 2007, Yuichi Nakamura wrote:
Just a couple more nits...
Quoted 8 lines
Quoted 6 lines
+#define
AVTAB_HASH(keyp, mask)\
((keyp->target_class+ \
(keyp->target_type<< 2) + \
(keyp->source_type<< 9)) & \
-AVTAB_HASH_MASK)
+ mask)Can you make this a static inline ?
Changed it to static inline avtab_hash.
Quoted 6 lines
Review
Quoted 4 lines
(quoted diff) +3
-0+ if (rc) { + goto err; + }Don't need these braces.
Fixed.
Also fixed below
Quoted 11 lines
(quoted diff) +5
-1+ rc = avtab_alloc(a, nel); + if (rc) { + rc = -ENOMEM; + goto bad; + } - JamesSignature · 2 lines
James Morris <[email protected]>
Following is updated patch to 2.6.22.
--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)
security/selinux/ss/avtab.c +56 -22
@@ -12,24 +12,25 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> -#include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ -((keyp->target_class + \ - (keyp->target_type << 2) + \ - (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) -static struct kmem_cache *avtab_node_cachep; +static inline int avtab_hash (struct avtab_key *keyp,u16 mask) +{ +return ((keyp->target_class + (keyp->target_type <<2 ) + \ + (keyp->source_type <<9 )) & mask); +} +static struct avtab_node * avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
@@ -62,7 +63,7 @@ static int avtab_insert(struct avtab *h,if (!h)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -102,7 +103,7 @@ avtab_insert_nonunique(struct avtab * h,if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -135,7 +136,7 @@ struct avtab_datum *avtab_search(structif (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -170,7 +171,7 @@ avtab_search_node(struct avtab *h, strucif (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;
@@ -237,32 +238,58 @@ void avtab_destroy(struct avtab *h) } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { -int i; + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} + +int avtab_alloc (struct avtab *h,int nrules) +{ +u16 mask; +u32 shift =0 ; +u32 work = nrules; +u32 nslot; + +while (work) { + work = work>>1 ; + shift++; + } +if (shift >2 ) + shift = shift -2 ; + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) + nslot =MAX_AVTAB_SIZE ; + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kcalloc (nslot,sizeof (*(h->htable)),GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) - h->htable[i] =NULL ; h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated." +"Num of rules:%d\n" , h->nslot, nrules);return 0 ; }void avtab_hash_eval (struct avtab *h,char *tag) {int i, chain_len, slots_used, max_chain_len; +unsigned long long chain2_len_sum;struct avtab_node *cur; slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { + chain2_len_sum =0 ; +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;
@@ -274,12 +301,14 @@ void avtab_hash_eval(struct avtab *h, chif (chain_len > max_chain_len) max_chain_len = chain_len; + chain2_len_sum += chain_len * chain_len; } }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , - max_chain_len); +"chain length %d sum of chain length^2 %Lu\n" , + tag, h->nel, slots_used, h->nslot, max_chain_len, + chain2_len_sum); }static uint16_t spec_order[] = {
@@ -419,6 +448,11 @@ int avtab_read(struct avtab *a, void *fp rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) + goto bad; +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {
security/selinux/ss/avtab.h +11 -5
@@ -16,6 +16,9 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #ifndef _SS_AVTAB_H_#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,int );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nexvoid avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */
security/selinux/ss/conditional.c +4 -0
@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) + goto err; +for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );if (!node)
security/selinux/ss/policydb.c +2 -5
@@ -176,18 +176,15 @@ static int policydb_init(struct policydb rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
security/selinux/ss/avtab.c void avtab_destroy(struct avtab *h) · line 254
Quoted 13 lines · Yuichi Nakamura
Following is updated patch to 2.6.22.
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +1
-0+int avtab_alloc (struct avtab *h,int nrules)
nrules should be u32 too.
And you should likely test for the degenerate case (nrules == 0) and bail on it.
Quoted 159 lines
security/selinux/ss/avtab.c +33
-6+{ +u16 mask; +u32 shift =0 ; +u32 work = nrules; +u32 nslot; + +while (work) { + work = work>>1 ; + shift++; + } +if (shift >2 ) + shift = shift -2 ; + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) + nslot =MAX_AVTAB_SIZE ; + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kcalloc (nslot,sizeof (*(h->htable)),GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) - h->htable[i] =NULL ; h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated." +"Num of rules:%d\n" , h->nslot, nrules);return 0 ; }void avtab_hash_eval (struct avtab *h,char *tag) {int i, chain_len, slots_used, max_chain_len; +unsigned long long chain2_len_sum;struct avtab_node *cur; slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { + chain2_len_sum =0 ; +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;@@ -274,12 +301,14 @@ void avtab_hash_eval(struct avtab *h, chif (chain_len > max_chain_len) max_chain_len = chain_len; + chain2_len_sum += chain_len * chain_len; } }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , - max_chain_len); +"chain length %d sum of chain length^2 %Lu\n" , + tag, h->nel, slots_used, h->nslot, max_chain_len, + chain2_len_sum); }static uint16_t spec_order[] = {@@ -419,6 +448,11 @@ int avtab_read(struct avtab *a, void *fp rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) + goto bad; +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.hlinux-2.6.22/security/selinux/ss/avtab.hsecurity/selinux/ss/avtab.h +11
-5@@ -16,6 +16,9 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #ifndef _SS_AVTAB_H_#define _SS_AVTAB_H_@@ -50,9 +53,13 @@ struct avtab_node {struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,int );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nexvoid avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */ diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/conditional.clinux-2.6.22/security/selinux/ss/conditional.csecurity/selinux/ss/conditional.c +4
-0@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) + goto err; +for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );if (!node)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/policydb.clinux-2.6.22/security/selinux/ss/policydb.csecurity/selinux/ss/policydb.c +2
-5@@ -176,18 +176,15 @@ static int policydb_init(struct policydb rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);Regards,
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 16 lines · On Thu, 23 Aug 2007 09:15:25 -0400 Stephen Smalley wrote:
security/selinux/ss/avtab.c
Quoted 13 lines · Yuichi Nakamura
Following is updated patch to 2.6.22.
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +1
-0+int avtab_alloc (struct avtab *h,int nrules)nrules should be u32 too.
Fixed.
Quoted 3 lines
And you should likely test for the degenerate case (nrules == 0) and bail on it.
Checking nrules==0.
And also checking !h->htable like below in avtab_search_node etc.
- if (!h)
+ if (!h || !h->htable)
Following is updated patch.
From: Yuichi Nakamura <[email protected]>
This patch reduces memory usage of SELinux by tuning avtab. Number of hash slots in avtab was 32768. Unused slots used memory when number of rules is fewer. This patch decides number of hash slots dynamically based on number of rules. (chain length)^2 is also printed out in avtab_hash_eval to see standard deviation of avtab hash table.
--- security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 ++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 -- 4 files changed, 82 insertions(+), 36 deletions(-)
security/selinux/ss/avtab.c +65 -26
@@ -12,24 +12,25 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> -#include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ -((keyp->target_class + \ - (keyp->target_type << 2) + \ - (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) -static struct kmem_cache *avtab_node_cachep; +static inline int avtab_hash (struct avtab_key *keyp,u16 mask) +{ +return ((keyp->target_class + (keyp->target_type <<2 ) + + (keyp->source_type <<9 )) & mask); +} +static struct avtab_node * avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
@@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h,struct avtab_node *prev, *cur, *newnode;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h,struct avtab_node *prev, *cur, *newnode;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {
@@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(structstruct avtab_node *cur;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, strucstruct avtab_node *cur;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&
@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;
@@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h) } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { -int i; + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} + +int avtab_alloc (struct avtab *h,u32 nrules) +{ +u16 mask =0 ; +u32 shift =0 ; +u32 work = nrules; +u32 nslot =0 ; + +if (nrules ==0 ) + goto avtab_alloc_out; + +while (work) { + work = work >>1 ; + shift++; + } +if (shift >2 ) + shift = shift -2 ; + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) + nslot =MAX_AVTAB_SIZE ; + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kcalloc (nslot,sizeof (*(h->htable)),GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) - h->htable[i] =NULL ; + + avtab_alloc_out: h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated." +"Num of rules:%d\n" , h->nslot, nrules);return 0 ; }void avtab_hash_eval (struct avtab *h,char *tag) {int i, chain_len, slots_used, max_chain_len; +unsigned long long chain2_len_sum;struct avtab_node *cur; slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { + chain2_len_sum =0 ; +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;
@@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, chif (chain_len > max_chain_len) max_chain_len = chain_len; + chain2_len_sum += chain_len * chain_len; } }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , - max_chain_len); +"chain length %d sum of chain length^2 %Lu\n" , + tag, h->nel, slots_used, h->nslot, max_chain_len, + chain2_len_sum); }static uint16_t spec_order[] = {
@@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) + goto bad; +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {
security/selinux/ss/avtab.h +11 -5
@@ -16,6 +16,9 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #ifndef _SS_AVTAB_H_#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,u32 );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nexvoid avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */
security/selinux/ss/conditional.c +4 -0
@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) + goto err; +for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );if (!node)
security/selinux/ss/policydb.c +2 -5
@@ -176,18 +176,15 @@ static int policydb_init(struct policydb rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Stephen Smalley
Acked-byQuoted 31 lines · Yuichi Nakamura
Quoted 16 lines · On Thu, 23 Aug 2007 09:15:25 -0400 Stephen Smalley wrote:
security/selinux/ss/avtab.c
Quoted 13 lines · Yuichi Nakamura
Following is updated patch to 2.6.22.
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +1
-0+int avtab_alloc (struct avtab *h,int nrules)nrules should be u32 too.
Fixed.
Quoted 3 lines
And you should likely test for the degenerate case (nrules == 0) and bail on it.
Checking nrules==0.
And also checking !h->htable like below inavtab_search_nodeetc.(quoted diff) +1
-1- if (!h) + if (!h || !h->htable)Following is updated patch.
From: Yuichi Nakamura <[email protected]>
Quoted 7 lines
This patch reduces memory usage of SELinux by tuning avtab. Number of hash slots in avtab was 32768. Unused slots used memory when number of rules is fewer. This patch decides number of hash slots dynamically based on number of rules. (chain length)^2 is also printed out in
avtab_hash_evalto see standard deviation of avtab hash table.Signed-off-by Yuichi Nakamura<[email protected]>
Looks good, thanks.
Quoted 286 lines
--- security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 ++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 -- 4 files changed, 82 insertions(+), 36 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +65
-26@@ -12,24 +12,25 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/errno.h> -#include "avtab.h" #include "policydb.h" -#define AVTAB_HASH (keyp) \ -((keyp->target_class + \ - (keyp->target_type << 2) + \ - (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) -static struct kmem_cache *avtab_node_cachep; +static inline int avtab_hash (struct avtab_key *keyp,u16 mask) +{ +return ((keyp->target_class + (keyp->target_type <<2 ) + + (keyp->source_type <<9 )) & mask); +} +static struct avtab_node * avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,@@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h,struct avtab_node *prev, *cur, *newnode;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return -EINVAL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {@@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h,struct avtab_node *prev, *cur, *newnode;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) {@@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(structstruct avtab_node *cur;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, strucstruct avtab_node *cur;u16 specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;@@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h) } h->htable[i] =NULL ; } -vfree (h->htable); +kfree (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; } -int avtab_init (struct avtab *h) { -int i; + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} + +int avtab_alloc (struct avtab *h,u32 nrules) +{ +u16 mask =0 ; +u32 shift =0 ; +u32 work = nrules; +u32 nslot =0 ; + +if (nrules ==0 ) + goto avtab_alloc_out; + +while (work) { + work = work >>1 ; + shift++; + } +if (shift >2 ) + shift = shift -2 ; + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) + nslot =MAX_AVTAB_SIZE ; + mask = nslot -1 ; - h->htable =vmalloc (sizeof (*(h->htable)) *AVTAB_SIZE ); + h->htable =kcalloc (nslot,sizeof (*(h->htable)),GFP_KERNEL );if (!h->htable)return -ENOMEM ; -for (i =0 ; i <AVTAB_SIZE ; i++) - h->htable[i] =NULL ; + + avtab_alloc_out: h->nel =0 ; + h->nslot = nslot; + h->mask = mask; +printk (KERN_DEBUG "SELinux:%d avtab hash slots allocated." +"Num of rules:%d\n" , h->nslot, nrules);return 0 ; }void avtab_hash_eval (struct avtab *h,char *tag) {int i, chain_len, slots_used, max_chain_len; +unsigned long long chain2_len_sum;struct avtab_node *cur; slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { + chain2_len_sum =0 ; +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;@@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, chif (chain_len > max_chain_len) max_chain_len = chain_len; + chain2_len_sum += chain_len * chain_len; } }printk (KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " -"chain length %d\n" , tag, h->nel, slots_used,AVTAB_SIZE , - max_chain_len); +"chain length %d sum of chain length^2 %Lu\n" , + tag, h->nel, slots_used, h->nslot, max_chain_len, + chain2_len_sum); }static uint16_t spec_order[] = {@@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp rc = -EINVAL ; goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) + goto bad; +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp,vers, a, avtab_insertf,NULL );if (rc) {diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.hlinux-2.6.22/security/selinux/ss/avtab.hsecurity/selinux/ss/avtab.h +11
-5@@ -16,6 +16,9 @@* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. +* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage */ #ifndef _SS_AVTAB_H_#define _SS_AVTAB_H_@@ -50,9 +53,13 @@ struct avtab_node {struct avtab {struct avtab_node **htable;u32 nel;/* number of elements */ +u32 nslot;/* number of hash slots */ +u16 mask;/* mask to compute hash func */ + };int avtab_init (struct avtab *); +int avtab_alloc (struct avtab *,u32 );struct avtab_datum *avtab_search (struct avtab *h,struct avtab_key *k);void avtab_destroy (struct avtab *h);void avtab_hash_eval (struct avtab *h,char *tag);@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_nexvoid avtab_cache_init (void );void avtab_cache_destroy (void ); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) - -#define AVTAB_SIZE AVTAB_HASH_BUCKETS +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS#endif /* _SS_AVTAB_H_ */ diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/conditional.clinux-2.6.22/security/selinux/ss/conditional.csecurity/selinux/ss/conditional.c +4
-0@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, v len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&(p->te_cond_avtab), p->te_avtab.nel); +if (rc) + goto err; +for (i =0 ; i < len; i++) { node =kzalloc (sizeof (struct cond_node ),GFP_KERNEL );if (!node)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/policydb.clinux-2.6.22/security/selinux/ss/policydb.csecurity/selinux/ss/policydb.c +2
-5@@ -176,18 +176,15 @@ static int policydb_init(struct policydb rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; -out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++)hashtab_destroy (p->symtab[i].table);Regards,
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 3 lines · Stephen Smalley
Looks good, thanks.
Acked-by Stephen Smalley <[email protected]>
Applied togit://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6.git#for-akpm
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 37 lines · Yuichi Nakamura
Quoted 16 lines · On Thu, 23 Aug 2007 09:15:25 -0400 Stephen Smalley wrote:
security/selinux/ss/avtab.c
Quoted 13 lines · Yuichi Nakamura
Following is updated patch to 2.6.22.
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +1
-0+int avtab_alloc (struct avtab *h,int nrules)nrules should be u32 too.
Fixed.
Quoted 3 lines
And you should likely test for the degenerate case (nrules == 0) and bail on it.
Checking nrules==0.
And also checking !h->htable like below inavtab_search_nodeetc.(quoted diff) +1
-1- if (!h) + if (!h || !h->htable)Following is updated patch.
From: Yuichi Nakamura <[email protected]>This patch reduces memory usage of SELinux by tuning avtab. Number of hash slots in avtab was 32768. Unused slots used memory when number of rules is fewer. This patch decides number of hash slots dynamically based on number of rules. (chain length)^2 is also printed out in
avtab_hash_evalto see standard deviation of avtab hash table.
Quoted 7 lines
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 ++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 -- 4 files changed, 82 insertions(+), 36 deletions(-)
Hi,
I'd like to apply the equivalent changes to libsepol, if you have no objection (note that libsepol is LGPL rather than GPL). A port of your patch to libsepol is below. This is to reduce memory usage by libsepol/libsemanage when reading in modules and policies. Is that ok with you?
checkpolicy/test/dispol.c | 2 libsepol/include/sepol/policydb/avtab.h | 18 ++++--- libsepol/src/avtab.c | 80 ++++++++++++++++++++++++-------- libsepol/src/conditional.c | 4 + libsepol/src/policydb.c | 7 -- libsepol/src/write.c | 11 ++-- 6 files changed, 85 insertions(+), 37 deletions(-)
include/sepol/policydb/avtab.h +12 -6
@@ -1,6 +1,11 @@/* Author : Stephen Smalley, <[email protected]> */ +/* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage +*/ +/* Updated: Frank Mayer <[email protected]> and Karl MacMillan <[email protected]> * * Added conditional policy language extensions
@@ -75,10 +80,12 @@typedef struct avtab {avtab_ptr_t *htable;uint32_t nel;/* number of elements */ +uint32_t nslot;/* number of hash slots */ +uint16_t mask;/* mask to compute hash func */ }avtab_t ;extern int avtab_init (avtab_t *); - +extern int avtab_alloc (avtab_t *,uint32_t );extern int avtab_insert (avtab_t * h,avtab_key_t * k,avtab_datum_t * d);extern avtab_datum_t *avtab_search (avtab_t * h,avtab_key_t * k);
@@ -110,12 +117,11 @@extern avtab_ptr_t avtab_search_node_next (avtab_ptr_t node,int specified); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS -#define AVTAB_SIZE AVTAB_HASH_BUCKETS -#endif /* _AVTAB_H_ */ /* FLASK */
src/conditional.c +4 -0
@@ -829,6 +829,10 @@ len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&p->te_cond_avtab, p->te_avtab.nel); +if (rc) + goto err; +for (i =0 ; i < len; i++) { node =malloc (sizeof (cond_node_t));if (!node)
src/policydb.c +2 -5
@@ -492,17 +492,14 @@ rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; - out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++) {hashtab_destroy (p->symtab[i].table);
src/write.c +6 -5
@@ -229,9 +229,9 @@static inline void avtab_reset_merged (avtab_t * a) { -int i; +unsigned int i;avtab_ptr_t cur; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < a->nslot; i++) {for (cur = a->htable[i]; cur; cur = cur->next) cur->merged =0 ; }
@@ -239,7 +239,8 @@static int avtab_write (struct policydb *p,avtab_t * a,struct policy_file *fp) { -int i, rc; +unsigned int i; +int rc;avtab_t expa;avtab_ptr_t cur;uint32_t nel;
@@ -269,7 +270,7 @@return POLICYDB_ERROR ; } -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < a->nslot; i++) {for (cur = a->htable[i]; cur; cur = cur->next) {/* If old format, compute final nel. If new format, write out the items. */
@@ -290,7 +291,7 @@ goto out; }avtab_reset_merged (a); -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < a->nslot; i++) {for (cur = a->htable[i]; cur; cur = cur->next) {if (avtab_write_item (p, cur, fp,1 ,1 ,NULL )) { rc =-1 ;
src/avtab.c +60 -20
175 lines not on this page · raw message
test/dispol.c +1 -1
@@ -169,7 +169,7 @@ }/* hmm...should have used avtab_map. */ -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < expa.nslot; i++) {for (cur = expa.htable[i]; cur; cur = cur->next) {render_av_rule (&cur->key, &cur->datum, what, p, fp); }
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 54 lines · Stephen Smalley
Quoted 37 lines · Yuichi Nakamura
Quoted 16 lines · On Thu, 23 Aug 2007 09:15:25 -0400 Stephen Smalley wrote:
security/selinux/ss/avtab.c
Quoted 13 lines · Yuichi Nakamura
Following is updated patch to 2.6.22.
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +1
-0+int avtab_alloc (struct avtab *h,int nrules)nrules should be u32 too.
Fixed.
Quoted 3 lines
And you should likely test for the degenerate case (nrules == 0) and bail on it.
Checking nrules==0.
And also checking !h->htable like below inavtab_search_nodeetc.(quoted diff) +1
-1- if (!h) + if (!h || !h->htable)Following is updated patch.
From: Yuichi Nakamura <[email protected]>This patch reduces memory usage of SELinux by tuning avtab. Number of hash slots in avtab was 32768. Unused slots used memory when number of rules is fewer. This patch decides number of hash slots dynamically based on number of rules. (chain length)^2 is also printed out in
avtab_hash_evalto see standard deviation of avtab hash table.Quoted 7 lines
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 ++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 -- 4 files changed, 82 insertions(+), 36 deletions(-)Hi,
I'd like to apply the equivalent changes to libsepol, if you have no objection (note that libsepol is LGPL rather than GPL). A port of your patch to libsepol is below. This is to reduce memory usage by libsepol/libsemanage when reading in modules and policies. Is that ok with you?
Quoted 7 lines
checkpolicy/test/dispol.c | 2 libsepol/include/sepol/policydb/avtab.h | 18 ++++--- libsepol/src/avtab.c | 80 ++++++++++++++++++++++++-------- libsepol/src/conditional.c | 4 + libsepol/src/policydb.c | 7 -- libsepol/src/write.c | 11 ++-- 6 files changed, 85 insertions(+), 37 deletions(-)
Some further fixes below, relative to the prior patch.
src/avtab.c +4 -4
@@ -85,7 +85,7 @@uint16_t specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return SEPOL_ENOMEM ; hvalue =avtab_hash (key, h->mask);
@@ -126,7 +126,7 @@uint16_t specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; hvalue =avtab_hash (key, h->mask); for (prev = NULL, cur = h->htable[hvalue];
@@ -158,7 +158,7 @@uint16_t specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; hvalue =avtab_hash (key, h->mask);
@@ -193,7 +193,7 @@uint16_t specified = key->specified & ~(AVTAB_ENABLED |AVTAB_ENABLED_OLD ); -if (!h) +if (!h || !h->htable)return NULL ; hvalue =avtab_hash (key, h->mask);
src/expand.c +10 -0
@@ -2137,6 +2138,16 @@avrule_block_t *curblock;int retval =-1 ; +if (avtab_alloc (&state->out->te_avtab,MAX_AVTAB_SIZE )) { +ERR (state->handle,"Out of Memory!" ); +return -1 ; + } + +if (avtab_alloc (&state->out->te_cond_avtab,MAX_AVTAB_SIZE )) { +ERR (state->handle,"Out of Memory!" ); +return -1 ; + } +for (curblock = state->base->global; curblock !=NULL ; curblock = curblock->next) {avrule_decl_t *decl = curblock->enabled;
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Hi.
Quoted 49 lines · On Thu, 31 Jan 2008 16:00:50 -0500 Stephen Smalley wrote:
Quoted 37 lines · Yuichi Nakamura
Quoted 16 lines · On Thu, 23 Aug 2007 09:15:25 -0400 Stephen Smalley wrote:
security/selinux/ss/avtab.c
Quoted 13 lines · Yuichi Nakamura
Following is updated patch to 2.6.22.
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 78 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 +++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 --- 4 files changed, 73 insertions(+), 32 deletions(-)diff -purN -X linux-2.6.22/Documentation/dontdiff
linux-2.6.22.orig/security/selinux/ss/avtab.clinux-2.6.22/security/selinux/ss/avtab.csecurity/selinux/ss/avtab.c +1
-0+int avtab_alloc (struct avtab *h,int nrules)nrules should be u32 too.
Fixed.
Quoted 3 lines
And you should likely test for the degenerate case (nrules == 0) and bail on it.
Checking nrules==0.
And also checking !h->htable like below inavtab_search_nodeetc.(quoted diff) +1
-1- if (!h) + if (!h || !h->htable)Following is updated patch.
From: Yuichi Nakamura <[email protected]>This patch reduces memory usage of SELinux by tuning avtab. Number of hash slots in avtab was 32768. Unused slots used memory when number of rules is fewer. This patch decides number of hash slots dynamically based on number of rules. (chain length)^2 is also printed out in
avtab_hash_evalto see standard deviation of avtab hash table.Quoted 7 lines
Signed-off-by Yuichi Nakamura<[email protected]>--- security/selinux/ss/avtab.c | 91 +++++++++++++++++++++++++++----------- security/selinux/ss/avtab.h | 16 ++++-- security/selinux/ss/conditional.c | 4 + security/selinux/ss/policydb.c | 7 -- 4 files changed, 82 insertions(+), 36 deletions(-)Hi,
Quoted 5 lines
I'd like to apply the equivalent changes to libsepol, if you have no objection (note that libsepol is LGPL rather than GPL). A port of your patch to libsepol is below. This is to reduce memory usage by libsepol/libsemanage when reading in modules and policies. Is that ok with you?
It is OK for me.
Please use the code.
Quoted 353 lines
checkpolicy/test/dispol.c | 2 libsepol/include/sepol/policydb/avtab.h | 18 ++++--- libsepol/src/avtab.c | 80 ++++++++++++++++++++++++-------- libsepol/src/conditional.c | 4 + libsepol/src/policydb.c | 7 -- libsepol/src/write.c | 11 ++-- 6 files changed, 85 insertions(+), 37 deletions(-)Index:
libsepol/include/sepol/policydb/avtab.h
===================================================================include/sepol/policydb/avtab.h +12
-6@@ -1,6 +1,11 @@/* Author : Stephen Smalley, <[email protected]> */ +/* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage +*/ +/* Updated: Frank Mayer <[email protected]> and Karl MacMillan <[email protected]> * * Added conditional policy language extensions @@ -75,10 +80,12 @@typedef struct avtab {avtab_ptr_t *htable;uint32_t nel;/* number of elements */ +uint32_t nslot;/* number of hash slots */ +uint16_t mask;/* mask to compute hash func */ }avtab_t ;extern int avtab_init (avtab_t *); - +extern int avtab_alloc (avtab_t *,uint32_t );extern int avtab_insert (avtab_t * h,avtab_key_t * k,avtab_datum_t * d);extern avtab_datum_t *avtab_search (avtab_t * h,avtab_key_t * k);@@ -110,12 +117,11 @@extern avtab_ptr_t avtab_search_node_next (avtab_ptr_t node,int specified); -#define AVTAB_HASH_BITS 15 -#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) -#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) +#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) +#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS -#define AVTAB_SIZE AVTAB_HASH_BUCKETS -#endif /* _AVTAB_H_ */ /* FLASK */ Index:
libsepol/src/conditional.c
===================================================================src/conditional.c +4
-0@@ -829,6 +829,10 @@ len =le32_to_cpu (buf[0 ]); + rc =avtab_alloc (&p->te_cond_avtab, p->te_avtab.nel); +if (rc) + goto err; +for (i =0 ; i < len; i++) { node =malloc (sizeof (cond_node_t));if (!node)Index:
libsepol/src/policydb.c
===================================================================src/policydb.c +2
-5@@ -492,17 +492,14 @@ rc =roles_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; rc =cond_policydb_init (p);if (rc) - goto out_free_avtab; + goto out_free_symtab; out:return rc; - out_free_avtab: -avtab_destroy (&p->te_avtab); - out_free_symtab:for (i =0 ; i <SYM_NUM ; i++) {hashtab_destroy (p->symtab[i].table);Index:
libsepol/src/write.c
===================================================================src/write.c +6
-5@@ -229,9 +229,9 @@static inline void avtab_reset_merged (avtab_t * a) { -int i; +unsigned int i;avtab_ptr_t cur; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < a->nslot; i++) {for (cur = a->htable[i]; cur; cur = cur->next) cur->merged =0 ; }@@ -239,7 +239,8 @@static int avtab_write (struct policydb *p,avtab_t * a,struct policy_file *fp) { -int i, rc; +unsigned int i; +int rc;avtab_t expa;avtab_ptr_t cur;uint32_t nel;@@ -269,7 +270,7 @@return POLICYDB_ERROR ; } -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < a->nslot; i++) {for (cur = a->htable[i]; cur; cur = cur->next) {/* If old format, compute final nel. If new format, write out the items. */ @@ -290,7 +291,7 @@ goto out; }avtab_reset_merged (a); -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < a->nslot; i++) {for (cur = a->htable[i]; cur; cur = cur->next) {if (avtab_write_item (p, cur, fp,1 ,1 ,NULL )) { rc =-1 ;Index:
libsepol/src/avtab.c
===================================================================src/avtab.c +60
-20@@ -1,6 +1,11 @@/* Author : Stephen Smalley, <[email protected]> */ +/* +* Updated: Yuichi Nakamura <[email protected]> +* Tuned number of hash slots for avtab to reduce memory usage +*/ +/* Updated: Frank Mayer <[email protected]> * and Karl MacMillan <[email protected]> * @@ -44,11 +49,11 @@#include "debug.h" #include "private.h" -#define AVTAB_HASH (keyp) \ -((keyp->target_class + \ - (keyp->target_type << 2) + \ - (keyp->source_type << 9)) & \ - AVTAB_HASH_MASK) +static inline int avtab_hash (struct avtab_key *keyp,uint16_t mask) +{ +return ((keyp->target_class + (keyp->target_type <<2 ) + + (keyp->source_type <<9 )) & mask); +} static avtab_ptr_t avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,@@ -83,7 +88,7 @@if (!h)return SEPOL_ENOMEM ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) { if (key->source_type == cur->key.source_type &&@@ -123,7 +128,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (prev =NULL , cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) { if (key->source_type == cur->key.source_type &&@@ -156,7 +161,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -191,7 +196,7 @@if (!h)return NULL ; - hvalue =AVTAB_HASH (key); + hvalue =avtab_hash (key, h->mask);for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type &&@@ -242,13 +247,13 @@void avtab_destroy (avtab_t * h) { -int i; +unsigned int i;avtab_ptr_t cur, temp;if (!h || !h->htable)return ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { temp = cur;@@ -259,19 +264,22 @@ }free (h->htable); h->htable =NULL ; + h->nslot =0 ; + h->mask =0 ; }int avtab_map (avtab_t * h,int (*apply) (avtab_key_t * k,avtab_datum_t * d,void *args),void *args) { -int i, ret; +unsigned int i; +int ret;avtab_ptr_t cur;if (!h)return 0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];while (cur !=NULL ) { ret =apply (&cur->key, &cur->datum, args);@@ -285,25 +293,50 @@int avtab_init (avtab_t * h) { -int i; + h->htable =NULL ; + h->nel =0 ; +return 0 ; +} - h->htable =malloc (sizeof (avtab_ptr_t) *AVTAB_SIZE ); +int avtab_alloc (avtab_t *h,uint32_t nrules) +{ +uint16_t mask =0 ; +uint32_t shift =0 ; +uint32_t work = nrules; +uint32_t nslot =0 ; + +if (nrules ==0 ) + goto out; + +while (work) { + work = work >>1 ; + shift++; + } +if (shift >2 ) + shift = shift -2 ; + nslot =1 << shift; +if (nslot >MAX_AVTAB_SIZE ) + nslot =MAX_AVTAB_SIZE ; + mask = nslot -1 ; + + h->htable =calloc (nslot,sizeof (avtab_ptr_t));if (!h->htable)return -1 ; -for (i =0 ; i <AVTAB_SIZE ; i++) - h->htable[i] = (avtab_ptr_t )NULL ; +out: h->nel =0 ; + h->nslot = nslot; + h->mask = mask;return 0 ; }void avtab_hash_eval (avtab_t * h,char *tag) { -int i, chain_len, slots_used, max_chain_len; +unsigned int i, chain_len, slots_used, max_chain_len;avtab_ptr_t cur; slots_used =0 ; max_chain_len =0 ; -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < h->nslot; i++) { cur = h->htable[i];if (cur) { slots_used++;@@ -320,7 +353,7 @@printf ("%s: %d entries and %d/%d buckets used, longest chain length %d\n" , - tag, h->nel, slots_used,AVTAB_SIZE , max_chain_len); + tag, h->nel, slots_used, h->nslot, max_chain_len); }/* Ordering of datums in the original avtab format in the policy file. */ @@ -471,6 +504,13 @@ERR (fp->handle,"table is empty" ); goto bad; } + + rc =avtab_alloc (a, nel); +if (rc) { +ERR (fp->handle,"out of memory" ); + goto bad; + } +for (i =0 ; i < nel; i++) { rc =avtab_read_item (fp, vers, a, avtab_insertf,NULL );if (rc) {Index:
checkpolicy/test/dispol.c
===================================================================test/dispol.c +1
-1@@ -169,7 +169,7 @@ }/* hmm...should have used avtab_map. */ -for (i =0 ; i <AVTAB_SIZE ; i++) { +for (i =0 ; i < expa.nslot; i++) {for (cur = expa.htable[i]; cur; cur = cur->next) {render_av_rule (&cur->key, &cur->datum, what, p, fp); }Signature · 9 lines
-- Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
security/selinux/ss/avtab.c line 32
Quoted 5 lines · Yuichi Nakamura
security/selinux/ss/avtab.c +5
-0+static inline int avtab_hash (struct avtab_key *keyp,u16 mask) +{ +return ((keyp->target_class + (keyp->target_type <<2 ) + \ + (keyp->source_type <<9 )) & mask); +}
As you'll need to resubmit the patch, please remove the \ (I had fixed it up in my local tree).
Please also provide a short description of the patch (one paragraph at the most), to go in the git log.
- James
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 10 lines · On Thu, 23 Aug 2007 07:46:52 -0700 (PDT) James Morris wrote:
security/selinux/ss/avtab.c line 32
Quoted 5 lines · Yuichi Nakamura
security/selinux/ss/avtab.c +5
-0+static inline int avtab_hash (struct avtab_key *keyp,u16 mask) +{ +return ((keyp->target_class + (keyp->target_type <<2 ) + \ + (keyp->source_type <<9 )) & mask); +}As you'll need to resubmit the patch, please remove the \ (I had fixed it up in my local tree).
I will fix in next patch.
Quoted 2 lines
Please also provide a short description of the patch (one paragraph at the most), to go in the git log.
I see.
Quoted 5 lines
- James
Signature · 2 lines
James Morris <[email protected]>
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
security/selinux/ss/avtab.c int avtab_read(struct avtab *a, void *fp · line 457
Quoted 5 lines · Yuichi Nakamura
security/selinux/ss/avtab.c +5
-0+ rc =avtab_alloc (a, nel); +if (rc) { + rc = -ENOMEM ; + goto bad; + }
Please also just use the return code here.
- James
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 7 lines · Yuichi Nakamura
I compared 3 hash functions, default, jhash,
hash_long. default is defaultAVTAB_HASH.
jhash is function defined inlinux/jhash.h.hash_longis defined inlinux/hash.h, I used it like following.(int)(hash_long(((unsigned long)keyp->target_class)+ (((unsigned long)keyp->target_type)<<2)+ (((unsigned long)keyp->source_type)<<9) , bits))
A number of months ago, the SETools team also recognized the limitations of the current avtab hash function. Beginning with SETools 3.3 release, we use a different hashing routine that is better suited for refpolicy analysis. The following analysis may be of interest to those adjusting the kernel avtab.
0. Background
The existing AV table in the kernel uses a 15-bit hash key, constructed as:[0]
#define AVTAB_HASH(keyp) \ ((keyp->target_class + \ (keyp->target_type << 2) + \ (keyp->source_type << 9)) & \ AVTAB_HASH_MASK)
We identified these problems with this hashing function:
a. The majority of rules in refpolicy involve the object classes
process (value 2), file (6), and dir (7). Thus at least three bits are needed to best express the target class.
b. Refpolicy has roughly 2000 distinct types and attributes. Only 7
bits are preserved for source_type.
To our surprise, we discovered that for a particular policy with several hundred thousand rules, some buckets were empty, while others were nearly 200.[1] We measured the effectiveness of the hash table by way of calculating the standard deviation in bucket lengths; it was 65.8227.
1. Change in avtab size
Our first optimization was to increase the hash table size to 16 bits. As expected, this roughly halved the access time and bucket lengths. With this change, we discovered that some buckets were still unused; the longest chain, however, was still excessively long at 101. The standard deviation halved to 33.0038.
2. Alternative Hashing Function
In combination with the increase in hash table size, we devised this hashing function:[2]
#define AVTAB_HASH(keyp) \ ((((keyp->source_type & 0xff) << 8) | (keyp->target_type & 0xff)) ^ \ (keyp->target_class & 0xf) ^ \ AVTAB_HASH_MASK)
This routine keeps the lower eight bits of the source and target types, as well as the lower four bits of the target class. The algorithm itself is very fast due to bitwise logic.[3]
2. Evaluation
With this new hashing function, our calculated standard deviation dropped significantly, to 10.6086. With the aforementioned policy, the shortest chain was now 8, the longest slightly more at 112. This implies that the algorithm has better distribution than the original avtab algorithm. As expected, runtime was cut considerably, without further increasing the memory footprint of the avtab.
3. Applicability to Current Discussion
The SETools hashing algorithm is designed for a 16-bit hash. It could be applied to other bucket sizes by modding it against an appopriate prime number.
When choosing the hashing algorithm for the avtab, we recommend that the types of data be also considered. If it is known that policies will have thousands of types, the hashing function should reflect that information. Likewise, if most rules are clustered around a few object classes, those class values need to become better discriminators.[4] The hashing algorithm changes are independent of changes to the bitmap and can be implemented regardless of other patches.
[0] From Linux kernel 2.6.22.1 source, security/selinux/ss/avtab.c, lines 25-29.
[1] The precise policy used can be provided, if requiested.
[2] We actually hash conditional rules into the same avtab as unconditional rules; for brevity conditionals are not shown.
[3] On the x86 architecture, bitwise operations take a single cycle to complete.
[4] Another improvement would be to have an avalanche effect in the algorithm.
Signature · 6 lines
Jason Tang / [email protected] -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 86 lines · On Tue, 21 Aug 2007 15:43:20 -0400 "J. Tang" wrote:
Quoted 7 lines · Yuichi Nakamura
I compared 3 hash functions, default, jhash,
hash_long. default is defaultAVTAB_HASH.
jhash is function defined inlinux/jhash.h.hash_longis defined inlinux/hash.h, I used it like following.(int)(hash_long(((unsigned long)keyp->target_class)+ (((unsigned long)keyp->target_type)<<2)+ (((unsigned long)keyp->source_type)<<9) , bits))A number of months ago, the SETools team also recognized the limitations of the current avtab hash function. Beginning with SETools 3.3 release, we use a different hashing routine that is better suited for refpolicy analysis. The following analysis may be of interest to those adjusting the kernel avtab.
0. Background
The existing AV table in the kernel uses a 15-bit hash key, constructed as:[0]
#define AVTAB_HASH(keyp) \ ((keyp->target_class + \ (keyp->target_type << 2) + \ (keyp->source_type << 9)) & \ AVTAB_HASH_MASK)We identified these problems with this hashing function:
a. The majority of rules in refpolicy involve the object classes
process (value 2), file (6), and dir (7). Thus at least three bits are needed to best express the target class.b. Refpolicy has roughly 2000 distinct types and attributes. Only 7
bits are preserved forsource_type.To our surprise, we discovered that for a particular policy with several hundred thousand rules, some buckets were empty, while others were nearly 200.[1] We measured the effectiveness of the hash table by way of calculating the standard deviation in bucket lengths; it was 65.8227.
1. Change in avtab size
Our first optimization was to increase the hash table size to 16 bits. As expected, this roughly halved the access time and bucket lengths. With this change, we discovered that some buckets were still unused; the longest chain, however, was still excessively long at 101. The standard deviation halved to 33.0038.
2. Alternative Hashing Function
In combination with the increase in hash table size, we devised this hashing function:[2]
#define AVTAB_HASH(keyp) \ ((((keyp->source_type & 0xff) << 8) | (keyp->target_type & 0xff)) ^ \ (keyp->target_class & 0xf) ^ \ AVTAB_HASH_MASK)This routine keeps the lower eight bits of the source and target types, as well as the lower four bits of the target class. The algorithm itself is very fast due to bitwise logic.[3]
2. Evaluation
With this new hashing function, our calculated standard deviation dropped significantly, to 10.6086. With the aforementioned policy, the shortest chain was now 8, the longest slightly more at 112. This implies that the algorithm has better distribution than the original avtab algorithm. As expected, runtime was cut considerably, without further increasing the memory footprint of the avtab.
3. Applicability to Current Discussion
The SETools hashing algorithm is designed for a 16-bit hash. It could be applied to other bucket sizes by modding it against an appopriate prime number.
When choosing the hashing algorithm for the avtab, we recommend that the types of data be also considered. If it is known that policies will have thousands of types, the hashing function should reflect that information. Likewise, if most rules are clustered around a few object classes, those class values need to become better discriminators.[4] The hashing algorithm changes are independent of changes to the bitmap and can be implemented regardless of other patches.
Quoted 3 lines
[0] From Linux kernel 2.6.22.1 source,
security/selinux/ss/avtab.c, lines 25-29.
[1] The precise policy used can be provided, if requiested.
Thanks for interesting information.
I tried this hash function,
but I could not improve the standard deviation to selinux-policy-strict-2.4.6-80.fc6. Could you give me your policy?
Quoted 9 lines
[2] We actually hash conditional rules into the same avtab as unconditional rules; for brevity conditionals are not shown.
[3] On the x86 architecture, bitwise operations take a single cycle to complete.
[4] Another improvement would be to have an avalanche effect in the algorithm.Signature · 1 line
Jason Tang / [email protected]
Regards,
Signature · 10 lines
Yuichi Nakamura Hitachi Software Engineering Co., Ltd. Japan SELinux Users Group(JSELUG): http://www.selinux.gr.jp/ SELinux Policy Editor: http://seedit.sourceforge.net/ -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.