aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorpaul.moore@hp.com <paul.moore@hp.com>2006-10-04 11:46:31 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-10-12 02:59:29 -0400
commitffb733c65000ee701294f7b80c4eca2a5f335637 (patch)
treeedda8e25792fe4a7bf0c619787949291276b9ed7 /include
parentc25d5180441e344a3368d100c57f0a481c6944f7 (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 'include')
-rw-r--r--include/net/netlabel.h62
1 files changed, 47 insertions, 15 deletions
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index c63a58058e21..113337c27955 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -34,6 +34,7 @@
34#include <linux/net.h> 34#include <linux/net.h>
35#include <linux/skbuff.h> 35#include <linux/skbuff.h>
36#include <net/netlink.h> 36#include <net/netlink.h>
37#include <asm/atomic.h>
37 38
38/* 39/*
39 * NetLabel - A management interface for maintaining network packet label 40 * NetLabel - A management interface for maintaining network packet label
@@ -106,6 +107,7 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
106 107
107/* LSM security attributes */ 108/* LSM security attributes */
108struct netlbl_lsm_cache { 109struct netlbl_lsm_cache {
110 atomic_t refcount;
109 void (*free) (const void *data); 111 void (*free) (const void *data);
110 void *data; 112 void *data;
111}; 113};
@@ -117,7 +119,7 @@ struct netlbl_lsm_secattr {
117 unsigned char *mls_cat; 119 unsigned char *mls_cat;
118 size_t mls_cat_len; 120 size_t mls_cat_len;
119 121
120 struct netlbl_lsm_cache cache; 122 struct netlbl_lsm_cache *cache;
121}; 123};
122 124
123/* 125/*
@@ -126,6 +128,43 @@ struct netlbl_lsm_secattr {
126 128
127 129
128/** 130/**
131 * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache
132 * @flags: the memory allocation flags
133 *
134 * Description:
135 * Allocate and initialize a netlbl_lsm_cache structure. Returns a pointer
136 * on success, NULL on failure.
137 *
138 */
139static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(int flags)
140{
141 struct netlbl_lsm_cache *cache;
142
143 cache = kzalloc(sizeof(*cache), flags);
144 if (cache)
145 atomic_set(&cache->refcount, 1);
146 return cache;
147}
148
149/**
150 * netlbl_secattr_cache_free - Frees a netlbl_lsm_cache struct
151 * @cache: the struct to free
152 *
153 * Description:
154 * Frees @secattr including all of the internal buffers.
155 *
156 */
157static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
158{
159 if (!atomic_dec_and_test(&cache->refcount))
160 return;
161
162 if (cache->free)
163 cache->free(cache->data);
164 kfree(cache);
165}
166
167/**
129 * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct 168 * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
130 * @secattr: the struct to initialize 169 * @secattr: the struct to initialize
131 * 170 *
@@ -143,20 +182,16 @@ static inline int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
143/** 182/**
144 * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct 183 * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct
145 * @secattr: the struct to clear 184 * @secattr: the struct to clear
146 * @clear_cache: cache clear flag
147 * 185 *
148 * Description: 186 * Description:
149 * Destroys the @secattr struct, including freeing all of the internal buffers. 187 * Destroys the @secattr struct, including freeing all of the internal buffers.
150 * If @clear_cache is true then free the cache fields, otherwise leave them 188 * The struct must be reset with a call to netlbl_secattr_init() before reuse.
151 * intact. The struct must be reset with a call to netlbl_secattr_init()
152 * before reuse.
153 * 189 *
154 */ 190 */
155static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr, 191static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
156 u32 clear_cache)
157{ 192{
158 if (clear_cache && secattr->cache.data != NULL && secattr->cache.free) 193 if (secattr->cache)
159 secattr->cache.free(secattr->cache.data); 194 netlbl_secattr_cache_free(secattr->cache);
160 kfree(secattr->domain); 195 kfree(secattr->domain);
161 kfree(secattr->mls_cat); 196 kfree(secattr->mls_cat);
162} 197}
@@ -178,17 +213,14 @@ static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(int flags)
178/** 213/**
179 * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct 214 * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct
180 * @secattr: the struct to free 215 * @secattr: the struct to free
181 * @clear_cache: cache clear flag
182 * 216 *
183 * Description: 217 * Description:
184 * Frees @secattr including all of the internal buffers. If @clear_cache is 218 * Frees @secattr including all of the internal buffers.
185 * true then free the cache fields, otherwise leave them intact.
186 * 219 *
187 */ 220 */
188static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr, 221static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
189 u32 clear_cache)
190{ 222{
191 netlbl_secattr_destroy(secattr, clear_cache); 223 netlbl_secattr_destroy(secattr);
192 kfree(secattr); 224 kfree(secattr);
193} 225}
194 226