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 /security | |
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 'security')
-rw-r--r-- | security/selinux/ss/services.c | 37 |
1 files changed, 21 insertions, 16 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 0c219a1b3243..bb2d2bc869ba 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2172,7 +2172,12 @@ struct netlbl_cache { | |||
2172 | */ | 2172 | */ |
2173 | static void selinux_netlbl_cache_free(const void *data) | 2173 | static void selinux_netlbl_cache_free(const void *data) |
2174 | { | 2174 | { |
2175 | struct netlbl_cache *cache = NETLBL_CACHE(data); | 2175 | struct netlbl_cache *cache; |
2176 | |||
2177 | if (data == NULL) | ||
2178 | return; | ||
2179 | |||
2180 | cache = NETLBL_CACHE(data); | ||
2176 | switch (cache->type) { | 2181 | switch (cache->type) { |
2177 | case NETLBL_CACHE_T_MLS: | 2182 | case NETLBL_CACHE_T_MLS: |
2178 | ebitmap_destroy(&cache->data.mls_label.level[0].cat); | 2183 | ebitmap_destroy(&cache->data.mls_label.level[0].cat); |
@@ -2197,17 +2202,20 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx) | |||
2197 | struct netlbl_lsm_secattr secattr; | 2202 | struct netlbl_lsm_secattr secattr; |
2198 | 2203 | ||
2199 | netlbl_secattr_init(&secattr); | 2204 | netlbl_secattr_init(&secattr); |
2205 | secattr.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); | ||
2206 | if (secattr.cache == NULL) | ||
2207 | goto netlbl_cache_add_return; | ||
2200 | 2208 | ||
2201 | cache = kzalloc(sizeof(*cache), GFP_ATOMIC); | 2209 | cache = kzalloc(sizeof(*cache), GFP_ATOMIC); |
2202 | if (cache == NULL) | 2210 | if (cache == NULL) |
2203 | goto netlbl_cache_add_failure; | 2211 | goto netlbl_cache_add_return; |
2204 | secattr.cache.free = selinux_netlbl_cache_free; | 2212 | secattr.cache->free = selinux_netlbl_cache_free; |
2205 | secattr.cache.data = (void *)cache; | 2213 | secattr.cache->data = (void *)cache; |
2206 | 2214 | ||
2207 | cache->type = NETLBL_CACHE_T_MLS; | 2215 | cache->type = NETLBL_CACHE_T_MLS; |
2208 | if (ebitmap_cpy(&cache->data.mls_label.level[0].cat, | 2216 | if (ebitmap_cpy(&cache->data.mls_label.level[0].cat, |
2209 | &ctx->range.level[0].cat) != 0) | 2217 | &ctx->range.level[0].cat) != 0) |
2210 | goto netlbl_cache_add_failure; | 2218 | goto netlbl_cache_add_return; |
2211 | cache->data.mls_label.level[1].cat.highbit = | 2219 | cache->data.mls_label.level[1].cat.highbit = |
2212 | cache->data.mls_label.level[0].cat.highbit; | 2220 | cache->data.mls_label.level[0].cat.highbit; |
2213 | cache->data.mls_label.level[1].cat.node = | 2221 | cache->data.mls_label.level[1].cat.node = |
@@ -2215,13 +2223,10 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx) | |||
2215 | cache->data.mls_label.level[0].sens = ctx->range.level[0].sens; | 2223 | cache->data.mls_label.level[0].sens = ctx->range.level[0].sens; |
2216 | cache->data.mls_label.level[1].sens = ctx->range.level[0].sens; | 2224 | cache->data.mls_label.level[1].sens = ctx->range.level[0].sens; |
2217 | 2225 | ||
2218 | if (netlbl_cache_add(skb, &secattr) != 0) | 2226 | netlbl_cache_add(skb, &secattr); |
2219 | goto netlbl_cache_add_failure; | ||
2220 | |||
2221 | return; | ||
2222 | 2227 | ||
2223 | netlbl_cache_add_failure: | 2228 | netlbl_cache_add_return: |
2224 | netlbl_secattr_destroy(&secattr, 1); | 2229 | netlbl_secattr_destroy(&secattr); |
2225 | } | 2230 | } |
2226 | 2231 | ||
2227 | /** | 2232 | /** |
@@ -2263,8 +2268,8 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb, | |||
2263 | 2268 | ||
2264 | POLICY_RDLOCK; | 2269 | POLICY_RDLOCK; |
2265 | 2270 | ||
2266 | if (secattr->cache.data) { | 2271 | if (secattr->cache) { |
2267 | cache = NETLBL_CACHE(secattr->cache.data); | 2272 | cache = NETLBL_CACHE(secattr->cache->data); |
2268 | switch (cache->type) { | 2273 | switch (cache->type) { |
2269 | case NETLBL_CACHE_T_SID: | 2274 | case NETLBL_CACHE_T_SID: |
2270 | *sid = cache->data.sid; | 2275 | *sid = cache->data.sid; |
@@ -2369,7 +2374,7 @@ static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
2369 | &secattr, | 2374 | &secattr, |
2370 | base_sid, | 2375 | base_sid, |
2371 | sid); | 2376 | sid); |
2372 | netlbl_secattr_destroy(&secattr, 0); | 2377 | netlbl_secattr_destroy(&secattr); |
2373 | 2378 | ||
2374 | return rc; | 2379 | return rc; |
2375 | } | 2380 | } |
@@ -2415,7 +2420,7 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) | |||
2415 | if (rc == 0) | 2420 | if (rc == 0) |
2416 | sksec->nlbl_state = NLBL_LABELED; | 2421 | sksec->nlbl_state = NLBL_LABELED; |
2417 | 2422 | ||
2418 | netlbl_secattr_destroy(&secattr, 0); | 2423 | netlbl_secattr_destroy(&secattr); |
2419 | 2424 | ||
2420 | netlbl_socket_setsid_return: | 2425 | netlbl_socket_setsid_return: |
2421 | POLICY_RDUNLOCK; | 2426 | POLICY_RDUNLOCK; |
@@ -2517,7 +2522,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | |||
2517 | sksec->sid, | 2522 | sksec->sid, |
2518 | &nlbl_peer_sid) == 0) | 2523 | &nlbl_peer_sid) == 0) |
2519 | sksec->peer_sid = nlbl_peer_sid; | 2524 | sksec->peer_sid = nlbl_peer_sid; |
2520 | netlbl_secattr_destroy(&secattr, 0); | 2525 | netlbl_secattr_destroy(&secattr); |
2521 | 2526 | ||
2522 | sksec->nlbl_state = NLBL_REQUIRE; | 2527 | sksec->nlbl_state = NLBL_REQUIRE; |
2523 | 2528 | ||