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 /include/net/netlabel.h | |
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 'include/net/netlabel.h')
-rw-r--r-- | include/net/netlabel.h | 62 |
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 */ |
108 | struct netlbl_lsm_cache { | 109 | struct 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 | */ | ||
139 | static 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 | */ | ||
157 | static 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 | */ |
155 | static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr, | 191 | static 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 | */ |
188 | static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr, | 221 | static 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 | ||