diff options
author | paul.moore@hp.com <paul.moore@hp.com> | 2006-10-04 11:46:31 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-10-12 02:59:29 -0400 |
commit | ffb733c65000ee701294f7b80c4eca2a5f335637 (patch) | |
tree | edda8e25792fe4a7bf0c619787949291276b9ed7 /net | |
parent | c25d5180441e344a3368d100c57f0a481c6944f7 (diff) |
NetLabel: fix a cache race condition
Testing revealed a problem with the NetLabel cache where a cached entry could
be freed while in use by the LSM layer causing an oops and other problems.
This patch fixes that problem by introducing a reference counter to the cache
entry so that it is only freed when it is no longer in use.
Signed-off-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 18 | ||||
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 2 |
2 files changed, 11 insertions, 9 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a8e2e879a647..bde8ccaa1531 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <net/tcp.h> | 43 | #include <net/tcp.h> |
44 | #include <net/netlabel.h> | 44 | #include <net/netlabel.h> |
45 | #include <net/cipso_ipv4.h> | 45 | #include <net/cipso_ipv4.h> |
46 | #include <asm/atomic.h> | ||
46 | #include <asm/bug.h> | 47 | #include <asm/bug.h> |
47 | 48 | ||
48 | struct cipso_v4_domhsh_entry { | 49 | struct cipso_v4_domhsh_entry { |
@@ -79,7 +80,7 @@ struct cipso_v4_map_cache_entry { | |||
79 | unsigned char *key; | 80 | unsigned char *key; |
80 | size_t key_len; | 81 | size_t key_len; |
81 | 82 | ||
82 | struct netlbl_lsm_cache lsm_data; | 83 | struct netlbl_lsm_cache *lsm_data; |
83 | 84 | ||
84 | u32 activity; | 85 | u32 activity; |
85 | struct list_head list; | 86 | struct list_head list; |
@@ -188,13 +189,14 @@ static void cipso_v4_doi_domhsh_free(struct rcu_head *entry) | |||
188 | * @entry: the entry to free | 189 | * @entry: the entry to free |
189 | * | 190 | * |
190 | * Description: | 191 | * Description: |
191 | * This function frees the memory associated with a cache entry. | 192 | * This function frees the memory associated with a cache entry including the |
193 | * LSM cache data if there are no longer any users, i.e. reference count == 0. | ||
192 | * | 194 | * |
193 | */ | 195 | */ |
194 | static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry) | 196 | static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry) |
195 | { | 197 | { |
196 | if (entry->lsm_data.free) | 198 | if (entry->lsm_data) |
197 | entry->lsm_data.free(entry->lsm_data.data); | 199 | netlbl_secattr_cache_free(entry->lsm_data); |
198 | kfree(entry->key); | 200 | kfree(entry->key); |
199 | kfree(entry); | 201 | kfree(entry); |
200 | } | 202 | } |
@@ -315,8 +317,8 @@ static int cipso_v4_cache_check(const unsigned char *key, | |||
315 | entry->key_len == key_len && | 317 | entry->key_len == key_len && |
316 | memcmp(entry->key, key, key_len) == 0) { | 318 | memcmp(entry->key, key, key_len) == 0) { |
317 | entry->activity += 1; | 319 | entry->activity += 1; |
318 | secattr->cache.free = entry->lsm_data.free; | 320 | atomic_inc(&entry->lsm_data->refcount); |
319 | secattr->cache.data = entry->lsm_data.data; | 321 | secattr->cache = entry->lsm_data; |
320 | if (prev_entry == NULL) { | 322 | if (prev_entry == NULL) { |
321 | spin_unlock_bh(&cipso_v4_cache[bkt].lock); | 323 | spin_unlock_bh(&cipso_v4_cache[bkt].lock); |
322 | return 0; | 324 | return 0; |
@@ -383,8 +385,8 @@ int cipso_v4_cache_add(const struct sk_buff *skb, | |||
383 | memcpy(entry->key, cipso_ptr, cipso_ptr_len); | 385 | memcpy(entry->key, cipso_ptr, cipso_ptr_len); |
384 | entry->key_len = cipso_ptr_len; | 386 | entry->key_len = cipso_ptr_len; |
385 | entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); | 387 | entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); |
386 | entry->lsm_data.free = secattr->cache.free; | 388 | atomic_inc(&secattr->cache->refcount); |
387 | entry->lsm_data.data = secattr->cache.data; | 389 | entry->lsm_data = secattr->cache; |
388 | 390 | ||
389 | bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); | 391 | bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); |
390 | spin_lock_bh(&cipso_v4_cache[bkt].lock); | 392 | spin_lock_bh(&cipso_v4_cache[bkt].lock); |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 54fb7de3c2b1..ff971103fd0c 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -200,7 +200,7 @@ void netlbl_cache_invalidate(void) | |||
200 | int netlbl_cache_add(const struct sk_buff *skb, | 200 | int netlbl_cache_add(const struct sk_buff *skb, |
201 | const struct netlbl_lsm_secattr *secattr) | 201 | const struct netlbl_lsm_secattr *secattr) |
202 | { | 202 | { |
203 | if (secattr->cache.data == NULL) | 203 | if (secattr->cache == NULL) |
204 | return -ENOMSG; | 204 | return -ENOMSG; |
205 | 205 | ||
206 | if (CIPSO_V4_OPTEXIST(skb)) | 206 | if (CIPSO_V4_OPTEXIST(skb)) |