diff options
| author | Michal Marek <mmarek@suse.cz> | 2010-10-27 18:15:57 -0400 |
|---|---|---|
| committer | Michal Marek <mmarek@suse.cz> | 2010-10-27 18:15:57 -0400 |
| commit | b74b953b998bcc2db91b694446f3a2619ec32de6 (patch) | |
| tree | 6ce24caabd730f6ae9287ed0676ec32e6ff31e9d /net/netlabel/netlabel_unlabeled.c | |
| parent | abb438526201c6a79949ad45375c051b6681c253 (diff) | |
| parent | f6f94e2ab1b33f0082ac22d71f66385a60d8157f (diff) | |
Merge commit 'v2.6.36' into kbuild/misc
Update to be able to fix a recent change to scripts/basic/docproc.c
(commit eda603f).
Diffstat (limited to 'net/netlabel/netlabel_unlabeled.c')
| -rw-r--r-- | net/netlabel/netlabel_unlabeled.c | 71 |
1 files changed, 20 insertions, 51 deletions
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 98ed22ee2ff4..e2b0a680dd56 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #include <linux/notifier.h> | 43 | #include <linux/notifier.h> |
| 44 | #include <linux/netdevice.h> | 44 | #include <linux/netdevice.h> |
| 45 | #include <linux/security.h> | 45 | #include <linux/security.h> |
| 46 | #include <linux/slab.h> | ||
| 46 | #include <net/sock.h> | 47 | #include <net/sock.h> |
| 47 | #include <net/netlink.h> | 48 | #include <net/netlink.h> |
| 48 | #include <net/genetlink.h> | 49 | #include <net/genetlink.h> |
| @@ -114,6 +115,9 @@ struct netlbl_unlhsh_walk_arg { | |||
| 114 | /* updates should be so rare that having one spinlock for the entire | 115 | /* updates should be so rare that having one spinlock for the entire |
| 115 | * hash table should be okay */ | 116 | * hash table should be okay */ |
| 116 | static DEFINE_SPINLOCK(netlbl_unlhsh_lock); | 117 | static DEFINE_SPINLOCK(netlbl_unlhsh_lock); |
| 118 | #define netlbl_unlhsh_rcu_deref(p) \ | ||
| 119 | rcu_dereference_check(p, rcu_read_lock_held() || \ | ||
| 120 | lockdep_is_held(&netlbl_unlhsh_lock)) | ||
| 117 | static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL; | 121 | static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL; |
| 118 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL; | 122 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL; |
| 119 | 123 | ||
| @@ -235,15 +239,13 @@ static void netlbl_unlhsh_free_iface(struct rcu_head *entry) | |||
| 235 | * Description: | 239 | * Description: |
| 236 | * This is the hashing function for the unlabeled hash table, it returns the | 240 | * This is the hashing function for the unlabeled hash table, it returns the |
| 237 | * bucket number for the given device/interface. The caller is responsible for | 241 | * bucket number for the given device/interface. The caller is responsible for |
| 238 | * calling the rcu_read_[un]lock() functions. | 242 | * ensuring that the hash table is protected with either a RCU read lock or |
| 243 | * the hash table lock. | ||
| 239 | * | 244 | * |
| 240 | */ | 245 | */ |
| 241 | static u32 netlbl_unlhsh_hash(int ifindex) | 246 | static u32 netlbl_unlhsh_hash(int ifindex) |
| 242 | { | 247 | { |
| 243 | /* this is taken _almost_ directly from | 248 | return ifindex & (netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->size - 1); |
| 244 | * security/selinux/netif.c:sel_netif_hasfn() as they do pretty much | ||
| 245 | * the same thing */ | ||
| 246 | return ifindex & (rcu_dereference(netlbl_unlhsh)->size - 1); | ||
| 247 | } | 249 | } |
| 248 | 250 | ||
| 249 | /** | 251 | /** |
| @@ -253,7 +255,8 @@ static u32 netlbl_unlhsh_hash(int ifindex) | |||
| 253 | * Description: | 255 | * Description: |
| 254 | * Searches the unlabeled connection hash table and returns a pointer to the | 256 | * Searches the unlabeled connection hash table and returns a pointer to the |
| 255 | * interface entry which matches @ifindex, otherwise NULL is returned. The | 257 | * interface entry which matches @ifindex, otherwise NULL is returned. The |
| 256 | * caller is responsible for calling the rcu_read_[un]lock() functions. | 258 | * caller is responsible for ensuring that the hash table is protected with |
| 259 | * either a RCU read lock or the hash table lock. | ||
| 257 | * | 260 | * |
| 258 | */ | 261 | */ |
| 259 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | 262 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) |
| @@ -263,7 +266,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | |||
| 263 | struct netlbl_unlhsh_iface *iter; | 266 | struct netlbl_unlhsh_iface *iter; |
| 264 | 267 | ||
| 265 | bkt = netlbl_unlhsh_hash(ifindex); | 268 | bkt = netlbl_unlhsh_hash(ifindex); |
| 266 | bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt]; | 269 | bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]; |
| 267 | list_for_each_entry_rcu(iter, bkt_list, list) | 270 | list_for_each_entry_rcu(iter, bkt_list, list) |
| 268 | if (iter->valid && iter->ifindex == ifindex) | 271 | if (iter->valid && iter->ifindex == ifindex) |
| 269 | return iter; | 272 | return iter; |
| @@ -272,33 +275,6 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | |||
| 272 | } | 275 | } |
| 273 | 276 | ||
| 274 | /** | 277 | /** |
| 275 | * netlbl_unlhsh_search_iface_def - Search for a matching interface entry | ||
| 276 | * @ifindex: the network interface | ||
| 277 | * | ||
| 278 | * Description: | ||
| 279 | * Searches the unlabeled connection hash table and returns a pointer to the | ||
| 280 | * interface entry which matches @ifindex. If an exact match can not be found | ||
| 281 | * and there is a valid default entry, the default entry is returned, otherwise | ||
| 282 | * NULL is returned. The caller is responsible for calling the | ||
| 283 | * rcu_read_[un]lock() functions. | ||
| 284 | * | ||
| 285 | */ | ||
| 286 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex) | ||
| 287 | { | ||
| 288 | struct netlbl_unlhsh_iface *entry; | ||
| 289 | |||
| 290 | entry = netlbl_unlhsh_search_iface(ifindex); | ||
| 291 | if (entry != NULL) | ||
| 292 | return entry; | ||
| 293 | |||
| 294 | entry = rcu_dereference(netlbl_unlhsh_def); | ||
| 295 | if (entry != NULL && entry->valid) | ||
| 296 | return entry; | ||
| 297 | |||
| 298 | return NULL; | ||
| 299 | } | ||
| 300 | |||
| 301 | /** | ||
| 302 | * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table | 278 | * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table |
| 303 | * @iface: the associated interface entry | 279 | * @iface: the associated interface entry |
| 304 | * @addr: IPv4 address in network byte order | 280 | * @addr: IPv4 address in network byte order |
| @@ -308,8 +284,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex) | |||
| 308 | * Description: | 284 | * Description: |
| 309 | * Add a new address entry into the unlabeled connection hash table using the | 285 | * Add a new address entry into the unlabeled connection hash table using the |
| 310 | * interface entry specified by @iface. On success zero is returned, otherwise | 286 | * interface entry specified by @iface. On success zero is returned, otherwise |
| 311 | * a negative value is returned. The caller is responsible for calling the | 287 | * a negative value is returned. |
| 312 | * rcu_read_[un]lock() functions. | ||
| 313 | * | 288 | * |
| 314 | */ | 289 | */ |
| 315 | static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, | 290 | static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, |
| @@ -327,7 +302,6 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, | |||
| 327 | entry->list.addr = addr->s_addr & mask->s_addr; | 302 | entry->list.addr = addr->s_addr & mask->s_addr; |
| 328 | entry->list.mask = mask->s_addr; | 303 | entry->list.mask = mask->s_addr; |
| 329 | entry->list.valid = 1; | 304 | entry->list.valid = 1; |
| 330 | INIT_RCU_HEAD(&entry->rcu); | ||
| 331 | entry->secid = secid; | 305 | entry->secid = secid; |
| 332 | 306 | ||
| 333 | spin_lock(&netlbl_unlhsh_lock); | 307 | spin_lock(&netlbl_unlhsh_lock); |
| @@ -350,8 +324,7 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, | |||
| 350 | * Description: | 324 | * Description: |
| 351 | * Add a new address entry into the unlabeled connection hash table using the | 325 | * Add a new address entry into the unlabeled connection hash table using the |
| 352 | * interface entry specified by @iface. On success zero is returned, otherwise | 326 | * interface entry specified by @iface. On success zero is returned, otherwise |
| 353 | * a negative value is returned. The caller is responsible for calling the | 327 | * a negative value is returned. |
| 354 | * rcu_read_[un]lock() functions. | ||
| 355 | * | 328 | * |
| 356 | */ | 329 | */ |
| 357 | static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, | 330 | static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, |
| @@ -373,7 +346,6 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, | |||
| 373 | entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; | 346 | entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; |
| 374 | ipv6_addr_copy(&entry->list.mask, mask); | 347 | ipv6_addr_copy(&entry->list.mask, mask); |
| 375 | entry->list.valid = 1; | 348 | entry->list.valid = 1; |
| 376 | INIT_RCU_HEAD(&entry->rcu); | ||
| 377 | entry->secid = secid; | 349 | entry->secid = secid; |
| 378 | 350 | ||
| 379 | spin_lock(&netlbl_unlhsh_lock); | 351 | spin_lock(&netlbl_unlhsh_lock); |
| @@ -393,8 +365,7 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, | |||
| 393 | * Description: | 365 | * Description: |
| 394 | * Add a new, empty, interface entry into the unlabeled connection hash table. | 366 | * Add a new, empty, interface entry into the unlabeled connection hash table. |
| 395 | * On success a pointer to the new interface entry is returned, on failure NULL | 367 | * On success a pointer to the new interface entry is returned, on failure NULL |
| 396 | * is returned. The caller is responsible for calling the rcu_read_[un]lock() | 368 | * is returned. |
| 397 | * functions. | ||
| 398 | * | 369 | * |
| 399 | */ | 370 | */ |
| 400 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) | 371 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) |
| @@ -410,7 +381,6 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) | |||
| 410 | INIT_LIST_HEAD(&iface->addr4_list); | 381 | INIT_LIST_HEAD(&iface->addr4_list); |
| 411 | INIT_LIST_HEAD(&iface->addr6_list); | 382 | INIT_LIST_HEAD(&iface->addr6_list); |
| 412 | iface->valid = 1; | 383 | iface->valid = 1; |
| 413 | INIT_RCU_HEAD(&iface->rcu); | ||
| 414 | 384 | ||
| 415 | spin_lock(&netlbl_unlhsh_lock); | 385 | spin_lock(&netlbl_unlhsh_lock); |
| 416 | if (ifindex > 0) { | 386 | if (ifindex > 0) { |
| @@ -418,10 +388,10 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) | |||
| 418 | if (netlbl_unlhsh_search_iface(ifindex) != NULL) | 388 | if (netlbl_unlhsh_search_iface(ifindex) != NULL) |
| 419 | goto add_iface_failure; | 389 | goto add_iface_failure; |
| 420 | list_add_tail_rcu(&iface->list, | 390 | list_add_tail_rcu(&iface->list, |
| 421 | &rcu_dereference(netlbl_unlhsh)->tbl[bkt]); | 391 | &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]); |
| 422 | } else { | 392 | } else { |
| 423 | INIT_LIST_HEAD(&iface->list); | 393 | INIT_LIST_HEAD(&iface->list); |
| 424 | if (rcu_dereference(netlbl_unlhsh_def) != NULL) | 394 | if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL) |
| 425 | goto add_iface_failure; | 395 | goto add_iface_failure; |
| 426 | rcu_assign_pointer(netlbl_unlhsh_def, iface); | 396 | rcu_assign_pointer(netlbl_unlhsh_def, iface); |
| 427 | } | 397 | } |
| @@ -551,8 +521,7 @@ unlhsh_add_return: | |||
| 551 | * | 521 | * |
| 552 | * Description: | 522 | * Description: |
| 553 | * Remove an IP address entry from the unlabeled connection hash table. | 523 | * Remove an IP address entry from the unlabeled connection hash table. |
| 554 | * Returns zero on success, negative values on failure. The caller is | 524 | * Returns zero on success, negative values on failure. |
| 555 | * responsible for calling the rcu_read_[un]lock() functions. | ||
| 556 | * | 525 | * |
| 557 | */ | 526 | */ |
| 558 | static int netlbl_unlhsh_remove_addr4(struct net *net, | 527 | static int netlbl_unlhsh_remove_addr4(struct net *net, |
| @@ -614,8 +583,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, | |||
| 614 | * | 583 | * |
| 615 | * Description: | 584 | * Description: |
| 616 | * Remove an IP address entry from the unlabeled connection hash table. | 585 | * Remove an IP address entry from the unlabeled connection hash table. |
| 617 | * Returns zero on success, negative values on failure. The caller is | 586 | * Returns zero on success, negative values on failure. |
| 618 | * responsible for calling the rcu_read_[un]lock() functions. | ||
| 619 | * | 587 | * |
| 620 | */ | 588 | */ |
| 621 | static int netlbl_unlhsh_remove_addr6(struct net *net, | 589 | static int netlbl_unlhsh_remove_addr6(struct net *net, |
| @@ -702,7 +670,6 @@ static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) | |||
| 702 | 670 | ||
| 703 | unlhsh_condremove_failure: | 671 | unlhsh_condremove_failure: |
| 704 | spin_unlock(&netlbl_unlhsh_lock); | 672 | spin_unlock(&netlbl_unlhsh_lock); |
| 705 | return; | ||
| 706 | } | 673 | } |
| 707 | 674 | ||
| 708 | /** | 675 | /** |
| @@ -1550,8 +1517,10 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, | |||
| 1550 | struct netlbl_unlhsh_iface *iface; | 1517 | struct netlbl_unlhsh_iface *iface; |
| 1551 | 1518 | ||
| 1552 | rcu_read_lock(); | 1519 | rcu_read_lock(); |
| 1553 | iface = netlbl_unlhsh_search_iface_def(skb->skb_iif); | 1520 | iface = netlbl_unlhsh_search_iface(skb->skb_iif); |
| 1554 | if (iface == NULL) | 1521 | if (iface == NULL) |
| 1522 | iface = rcu_dereference(netlbl_unlhsh_def); | ||
| 1523 | if (iface == NULL || !iface->valid) | ||
| 1555 | goto unlabel_getattr_nolabel; | 1524 | goto unlabel_getattr_nolabel; |
| 1556 | switch (family) { | 1525 | switch (family) { |
| 1557 | case PF_INET: { | 1526 | case PF_INET: { |
