diff options
| -rw-r--r-- | net/netlabel/netlabel_domainhash.c | 28 | ||||
| -rw-r--r-- | net/netlabel/netlabel_unlabeled.c | 66 |
2 files changed, 37 insertions, 57 deletions
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 0bfeaab88ef5..06ab41b6b57a 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
| @@ -50,9 +50,12 @@ struct netlbl_domhsh_tbl { | |||
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | /* Domain hash table */ | 52 | /* Domain hash table */ |
| 53 | /* XXX - updates should be so rare that having one spinlock for the entire | 53 | /* updates should be so rare that having one spinlock for the entire hash table |
| 54 | * hash table should be okay */ | 54 | * should be okay */ |
| 55 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); | 55 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); |
| 56 | #define netlbl_domhsh_rcu_deref(p) \ | ||
| 57 | rcu_dereference_check(p, rcu_read_lock_held() || \ | ||
| 58 | lockdep_is_held(&netlbl_domhsh_lock)) | ||
| 56 | static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; | 59 | static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; |
| 57 | static struct netlbl_dom_map *netlbl_domhsh_def = NULL; | 60 | static struct netlbl_dom_map *netlbl_domhsh_def = NULL; |
| 58 | 61 | ||
| @@ -106,7 +109,8 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry) | |||
| 106 | * Description: | 109 | * Description: |
| 107 | * This is the hashing function for the domain hash table, it returns the | 110 | * This is the hashing function for the domain hash table, it returns the |
| 108 | * correct bucket number for the domain. The caller is responsibile for | 111 | * correct bucket number for the domain. The caller is responsibile for |
| 109 | * calling the rcu_read_[un]lock() functions. | 112 | * ensuring that the hash table is protected with either a RCU read lock or the |
| 113 | * hash table lock. | ||
| 110 | * | 114 | * |
| 111 | */ | 115 | */ |
| 112 | static u32 netlbl_domhsh_hash(const char *key) | 116 | static u32 netlbl_domhsh_hash(const char *key) |
| @@ -120,7 +124,7 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
| 120 | 124 | ||
| 121 | for (iter = 0, val = 0, len = strlen(key); iter < len; iter++) | 125 | for (iter = 0, val = 0, len = strlen(key); iter < len; iter++) |
| 122 | val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter]; | 126 | val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter]; |
| 123 | return val & (rcu_dereference(netlbl_domhsh)->size - 1); | 127 | return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1); |
| 124 | } | 128 | } |
| 125 | 129 | ||
| 126 | /** | 130 | /** |
| @@ -130,7 +134,8 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
| 130 | * Description: | 134 | * Description: |
| 131 | * Searches the domain hash table and returns a pointer to the hash table | 135 | * Searches the domain hash table and returns a pointer to the hash table |
| 132 | * entry if found, otherwise NULL is returned. The caller is responsibile for | 136 | * entry if found, otherwise NULL is returned. The caller is responsibile for |
| 133 | * the rcu hash table locks (i.e. the caller much call rcu_read_[un]lock()). | 137 | * ensuring that the hash table is protected with either a RCU read lock or the |
| 138 | * hash table lock. | ||
| 134 | * | 139 | * |
| 135 | */ | 140 | */ |
| 136 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | 141 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) |
| @@ -141,7 +146,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | |||
| 141 | 146 | ||
| 142 | if (domain != NULL) { | 147 | if (domain != NULL) { |
| 143 | bkt = netlbl_domhsh_hash(domain); | 148 | bkt = netlbl_domhsh_hash(domain); |
| 144 | bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; | 149 | bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt]; |
| 145 | list_for_each_entry_rcu(iter, bkt_list, list) | 150 | list_for_each_entry_rcu(iter, bkt_list, list) |
| 146 | if (iter->valid && strcmp(iter->domain, domain) == 0) | 151 | if (iter->valid && strcmp(iter->domain, domain) == 0) |
| 147 | return iter; | 152 | return iter; |
| @@ -159,8 +164,8 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | |||
| 159 | * Searches the domain hash table and returns a pointer to the hash table | 164 | * Searches the domain hash table and returns a pointer to the hash table |
| 160 | * entry if an exact match is found, if an exact match is not present in the | 165 | * entry if an exact match is found, if an exact match is not present in the |
| 161 | * hash table then the default entry is returned if valid otherwise NULL is | 166 | * hash table then the default entry is returned if valid otherwise NULL is |
| 162 | * returned. The caller is responsibile for the rcu hash table locks | 167 | * returned. The caller is responsibile ensuring that the hash table is |
| 163 | * (i.e. the caller much call rcu_read_[un]lock()). | 168 | * protected with either a RCU read lock or the hash table lock. |
| 164 | * | 169 | * |
| 165 | */ | 170 | */ |
| 166 | static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | 171 | static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) |
| @@ -169,7 +174,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | |||
| 169 | 174 | ||
| 170 | entry = netlbl_domhsh_search(domain); | 175 | entry = netlbl_domhsh_search(domain); |
| 171 | if (entry == NULL) { | 176 | if (entry == NULL) { |
| 172 | entry = rcu_dereference(netlbl_domhsh_def); | 177 | entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def); |
| 173 | if (entry != NULL && !entry->valid) | 178 | if (entry != NULL && !entry->valid) |
| 174 | entry = NULL; | 179 | entry = NULL; |
| 175 | } | 180 | } |
| @@ -306,8 +311,11 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, | |||
| 306 | struct netlbl_af6list *tmp6; | 311 | struct netlbl_af6list *tmp6; |
| 307 | #endif /* IPv6 */ | 312 | #endif /* IPv6 */ |
| 308 | 313 | ||
| 314 | /* XXX - we can remove this RCU read lock as the spinlock protects the | ||
| 315 | * entire function, but before we do we need to fixup the | ||
| 316 | * netlbl_af[4,6]list RCU functions to do "the right thing" with | ||
| 317 | * respect to rcu_dereference() when only a spinlock is held. */ | ||
| 309 | rcu_read_lock(); | 318 | rcu_read_lock(); |
| 310 | |||
| 311 | spin_lock(&netlbl_domhsh_lock); | 319 | spin_lock(&netlbl_domhsh_lock); |
| 312 | if (entry->domain != NULL) | 320 | if (entry->domain != NULL) |
| 313 | entry_old = netlbl_domhsh_search(entry->domain); | 321 | entry_old = netlbl_domhsh_search(entry->domain); |
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 852d9d7976b9..3b4fde7622a3 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c | |||
| @@ -114,6 +114,9 @@ struct netlbl_unlhsh_walk_arg { | |||
| 114 | /* updates should be so rare that having one spinlock for the entire | 114 | /* updates should be so rare that having one spinlock for the entire |
| 115 | * hash table should be okay */ | 115 | * hash table should be okay */ |
| 116 | static DEFINE_SPINLOCK(netlbl_unlhsh_lock); | 116 | static DEFINE_SPINLOCK(netlbl_unlhsh_lock); |
| 117 | #define netlbl_unlhsh_rcu_deref(p) \ | ||
| 118 | rcu_dereference_check(p, rcu_read_lock_held() || \ | ||
| 119 | lockdep_is_held(&netlbl_unlhsh_lock)) | ||
| 117 | static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL; | 120 | static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL; |
| 118 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL; | 121 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL; |
| 119 | 122 | ||
| @@ -235,15 +238,13 @@ static void netlbl_unlhsh_free_iface(struct rcu_head *entry) | |||
| 235 | * Description: | 238 | * Description: |
| 236 | * This is the hashing function for the unlabeled hash table, it returns the | 239 | * 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 | 240 | * bucket number for the given device/interface. The caller is responsible for |
| 238 | * calling the rcu_read_[un]lock() functions. | 241 | * ensuring that the hash table is protected with either a RCU read lock or |
| 242 | * the hash table lock. | ||
| 239 | * | 243 | * |
| 240 | */ | 244 | */ |
| 241 | static u32 netlbl_unlhsh_hash(int ifindex) | 245 | static u32 netlbl_unlhsh_hash(int ifindex) |
| 242 | { | 246 | { |
| 243 | /* this is taken _almost_ directly from | 247 | 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 | } | 248 | } |
| 248 | 249 | ||
| 249 | /** | 250 | /** |
| @@ -253,7 +254,8 @@ static u32 netlbl_unlhsh_hash(int ifindex) | |||
| 253 | * Description: | 254 | * Description: |
| 254 | * Searches the unlabeled connection hash table and returns a pointer to the | 255 | * Searches the unlabeled connection hash table and returns a pointer to the |
| 255 | * interface entry which matches @ifindex, otherwise NULL is returned. The | 256 | * interface entry which matches @ifindex, otherwise NULL is returned. The |
| 256 | * caller is responsible for calling the rcu_read_[un]lock() functions. | 257 | * caller is responsible for ensuring that the hash table is protected with |
| 258 | * either a RCU read lock or the hash table lock. | ||
| 257 | * | 259 | * |
| 258 | */ | 260 | */ |
| 259 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | 261 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) |
| @@ -263,7 +265,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | |||
| 263 | struct netlbl_unlhsh_iface *iter; | 265 | struct netlbl_unlhsh_iface *iter; |
| 264 | 266 | ||
| 265 | bkt = netlbl_unlhsh_hash(ifindex); | 267 | bkt = netlbl_unlhsh_hash(ifindex); |
| 266 | bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt]; | 268 | bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]; |
| 267 | list_for_each_entry_rcu(iter, bkt_list, list) | 269 | list_for_each_entry_rcu(iter, bkt_list, list) |
| 268 | if (iter->valid && iter->ifindex == ifindex) | 270 | if (iter->valid && iter->ifindex == ifindex) |
| 269 | return iter; | 271 | return iter; |
| @@ -272,33 +274,6 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) | |||
| 272 | } | 274 | } |
| 273 | 275 | ||
| 274 | /** | 276 | /** |
| 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 | 277 | * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table |
| 303 | * @iface: the associated interface entry | 278 | * @iface: the associated interface entry |
| 304 | * @addr: IPv4 address in network byte order | 279 | * @addr: IPv4 address in network byte order |
| @@ -308,8 +283,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex) | |||
| 308 | * Description: | 283 | * Description: |
| 309 | * Add a new address entry into the unlabeled connection hash table using the | 284 | * 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 | 285 | * interface entry specified by @iface. On success zero is returned, otherwise |
| 311 | * a negative value is returned. The caller is responsible for calling the | 286 | * a negative value is returned. |
| 312 | * rcu_read_[un]lock() functions. | ||
| 313 | * | 287 | * |
| 314 | */ | 288 | */ |
| 315 | static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, | 289 | static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, |
| @@ -349,8 +323,7 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, | |||
| 349 | * Description: | 323 | * Description: |
| 350 | * Add a new address entry into the unlabeled connection hash table using the | 324 | * Add a new address entry into the unlabeled connection hash table using the |
| 351 | * interface entry specified by @iface. On success zero is returned, otherwise | 325 | * interface entry specified by @iface. On success zero is returned, otherwise |
| 352 | * a negative value is returned. The caller is responsible for calling the | 326 | * a negative value is returned. |
| 353 | * rcu_read_[un]lock() functions. | ||
| 354 | * | 327 | * |
| 355 | */ | 328 | */ |
| 356 | static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, | 329 | static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, |
| @@ -391,8 +364,7 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, | |||
| 391 | * Description: | 364 | * Description: |
| 392 | * Add a new, empty, interface entry into the unlabeled connection hash table. | 365 | * Add a new, empty, interface entry into the unlabeled connection hash table. |
| 393 | * On success a pointer to the new interface entry is returned, on failure NULL | 366 | * On success a pointer to the new interface entry is returned, on failure NULL |
| 394 | * is returned. The caller is responsible for calling the rcu_read_[un]lock() | 367 | * is returned. |
| 395 | * functions. | ||
| 396 | * | 368 | * |
| 397 | */ | 369 | */ |
| 398 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) | 370 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) |
| @@ -415,10 +387,10 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) | |||
| 415 | if (netlbl_unlhsh_search_iface(ifindex) != NULL) | 387 | if (netlbl_unlhsh_search_iface(ifindex) != NULL) |
| 416 | goto add_iface_failure; | 388 | goto add_iface_failure; |
| 417 | list_add_tail_rcu(&iface->list, | 389 | list_add_tail_rcu(&iface->list, |
| 418 | &rcu_dereference(netlbl_unlhsh)->tbl[bkt]); | 390 | &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]); |
| 419 | } else { | 391 | } else { |
| 420 | INIT_LIST_HEAD(&iface->list); | 392 | INIT_LIST_HEAD(&iface->list); |
| 421 | if (rcu_dereference(netlbl_unlhsh_def) != NULL) | 393 | if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL) |
| 422 | goto add_iface_failure; | 394 | goto add_iface_failure; |
| 423 | rcu_assign_pointer(netlbl_unlhsh_def, iface); | 395 | rcu_assign_pointer(netlbl_unlhsh_def, iface); |
| 424 | } | 396 | } |
| @@ -548,8 +520,7 @@ unlhsh_add_return: | |||
| 548 | * | 520 | * |
| 549 | * Description: | 521 | * Description: |
| 550 | * Remove an IP address entry from the unlabeled connection hash table. | 522 | * Remove an IP address entry from the unlabeled connection hash table. |
| 551 | * Returns zero on success, negative values on failure. The caller is | 523 | * Returns zero on success, negative values on failure. |
| 552 | * responsible for calling the rcu_read_[un]lock() functions. | ||
| 553 | * | 524 | * |
| 554 | */ | 525 | */ |
| 555 | static int netlbl_unlhsh_remove_addr4(struct net *net, | 526 | static int netlbl_unlhsh_remove_addr4(struct net *net, |
| @@ -611,8 +582,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, | |||
| 611 | * | 582 | * |
| 612 | * Description: | 583 | * Description: |
| 613 | * Remove an IP address entry from the unlabeled connection hash table. | 584 | * Remove an IP address entry from the unlabeled connection hash table. |
| 614 | * Returns zero on success, negative values on failure. The caller is | 585 | * Returns zero on success, negative values on failure. |
| 615 | * responsible for calling the rcu_read_[un]lock() functions. | ||
| 616 | * | 586 | * |
| 617 | */ | 587 | */ |
| 618 | static int netlbl_unlhsh_remove_addr6(struct net *net, | 588 | static int netlbl_unlhsh_remove_addr6(struct net *net, |
| @@ -1547,8 +1517,10 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, | |||
| 1547 | struct netlbl_unlhsh_iface *iface; | 1517 | struct netlbl_unlhsh_iface *iface; |
| 1548 | 1518 | ||
| 1549 | rcu_read_lock(); | 1519 | rcu_read_lock(); |
| 1550 | iface = netlbl_unlhsh_search_iface_def(skb->skb_iif); | 1520 | iface = netlbl_unlhsh_search_iface(skb->skb_iif); |
| 1551 | if (iface == NULL) | 1521 | if (iface == NULL) |
| 1522 | iface = rcu_dereference(netlbl_unlhsh_def); | ||
| 1523 | if (iface == NULL || !iface->valid) | ||
| 1552 | goto unlabel_getattr_nolabel; | 1524 | goto unlabel_getattr_nolabel; |
| 1553 | switch (family) { | 1525 | switch (family) { |
| 1554 | case PF_INET: { | 1526 | case PF_INET: { |
