diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 96 |
1 files changed, 52 insertions, 44 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index c5a5165a5927..41eabc46f110 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -42,13 +42,12 @@ static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock); | |||
42 | static struct dst_entry *xfrm_policy_sk_bundles; | 42 | static struct dst_entry *xfrm_policy_sk_bundles; |
43 | static DEFINE_RWLOCK(xfrm_policy_lock); | 43 | static DEFINE_RWLOCK(xfrm_policy_lock); |
44 | 44 | ||
45 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | 45 | static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); |
46 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | 46 | static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] |
47 | __read_mostly; | ||
47 | 48 | ||
48 | static struct kmem_cache *xfrm_dst_cache __read_mostly; | 49 | static struct kmem_cache *xfrm_dst_cache __read_mostly; |
49 | 50 | ||
50 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | ||
51 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); | ||
52 | static void xfrm_init_pmtu(struct dst_entry *dst); | 51 | static void xfrm_init_pmtu(struct dst_entry *dst); |
53 | static int stale_bundle(struct dst_entry *dst); | 52 | static int stale_bundle(struct dst_entry *dst); |
54 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); | 53 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); |
@@ -95,6 +94,24 @@ bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl | |||
95 | return false; | 94 | return false; |
96 | } | 95 | } |
97 | 96 | ||
97 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) | ||
98 | { | ||
99 | struct xfrm_policy_afinfo *afinfo; | ||
100 | |||
101 | if (unlikely(family >= NPROTO)) | ||
102 | return NULL; | ||
103 | rcu_read_lock(); | ||
104 | afinfo = rcu_dereference(xfrm_policy_afinfo[family]); | ||
105 | if (unlikely(!afinfo)) | ||
106 | rcu_read_unlock(); | ||
107 | return afinfo; | ||
108 | } | ||
109 | |||
110 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) | ||
111 | { | ||
112 | rcu_read_unlock(); | ||
113 | } | ||
114 | |||
98 | static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, | 115 | static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, |
99 | const xfrm_address_t *saddr, | 116 | const xfrm_address_t *saddr, |
100 | const xfrm_address_t *daddr, | 117 | const xfrm_address_t *daddr, |
@@ -585,6 +602,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
585 | xfrm_pol_hold(policy); | 602 | xfrm_pol_hold(policy); |
586 | net->xfrm.policy_count[dir]++; | 603 | net->xfrm.policy_count[dir]++; |
587 | atomic_inc(&flow_cache_genid); | 604 | atomic_inc(&flow_cache_genid); |
605 | rt_genid_bump(net); | ||
588 | if (delpol) | 606 | if (delpol) |
589 | __xfrm_policy_unlink(delpol, dir); | 607 | __xfrm_policy_unlink(delpol, dir); |
590 | policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); | 608 | policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); |
@@ -1357,6 +1375,8 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) | |||
1357 | 1375 | ||
1358 | memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst)); | 1376 | memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst)); |
1359 | xdst->flo.ops = &xfrm_bundle_fc_ops; | 1377 | xdst->flo.ops = &xfrm_bundle_fc_ops; |
1378 | if (afinfo->init_dst) | ||
1379 | afinfo->init_dst(net, xdst); | ||
1360 | } else | 1380 | } else |
1361 | xdst = ERR_PTR(-ENOBUFS); | 1381 | xdst = ERR_PTR(-ENOBUFS); |
1362 | 1382 | ||
@@ -1761,7 +1781,7 @@ static struct dst_entry *make_blackhole(struct net *net, u16 family, | |||
1761 | 1781 | ||
1762 | if (!afinfo) { | 1782 | if (!afinfo) { |
1763 | dst_release(dst_orig); | 1783 | dst_release(dst_orig); |
1764 | ret = ERR_PTR(-EINVAL); | 1784 | return ERR_PTR(-EINVAL); |
1765 | } else { | 1785 | } else { |
1766 | ret = afinfo->blackhole_route(net, dst_orig); | 1786 | ret = afinfo->blackhole_route(net, dst_orig); |
1767 | } | 1787 | } |
@@ -2418,7 +2438,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2418 | return -EINVAL; | 2438 | return -EINVAL; |
2419 | if (unlikely(afinfo->family >= NPROTO)) | 2439 | if (unlikely(afinfo->family >= NPROTO)) |
2420 | return -EAFNOSUPPORT; | 2440 | return -EAFNOSUPPORT; |
2421 | write_lock_bh(&xfrm_policy_afinfo_lock); | 2441 | spin_lock(&xfrm_policy_afinfo_lock); |
2422 | if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL)) | 2442 | if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL)) |
2423 | err = -ENOBUFS; | 2443 | err = -ENOBUFS; |
2424 | else { | 2444 | else { |
@@ -2439,9 +2459,9 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2439 | dst_ops->neigh_lookup = xfrm_neigh_lookup; | 2459 | dst_ops->neigh_lookup = xfrm_neigh_lookup; |
2440 | if (likely(afinfo->garbage_collect == NULL)) | 2460 | if (likely(afinfo->garbage_collect == NULL)) |
2441 | afinfo->garbage_collect = xfrm_garbage_collect_deferred; | 2461 | afinfo->garbage_collect = xfrm_garbage_collect_deferred; |
2442 | xfrm_policy_afinfo[afinfo->family] = afinfo; | 2462 | rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family], afinfo); |
2443 | } | 2463 | } |
2444 | write_unlock_bh(&xfrm_policy_afinfo_lock); | 2464 | spin_unlock(&xfrm_policy_afinfo_lock); |
2445 | 2465 | ||
2446 | rtnl_lock(); | 2466 | rtnl_lock(); |
2447 | for_each_net(net) { | 2467 | for_each_net(net) { |
@@ -2474,21 +2494,26 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2474 | return -EINVAL; | 2494 | return -EINVAL; |
2475 | if (unlikely(afinfo->family >= NPROTO)) | 2495 | if (unlikely(afinfo->family >= NPROTO)) |
2476 | return -EAFNOSUPPORT; | 2496 | return -EAFNOSUPPORT; |
2477 | write_lock_bh(&xfrm_policy_afinfo_lock); | 2497 | spin_lock(&xfrm_policy_afinfo_lock); |
2478 | if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) { | 2498 | if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) { |
2479 | if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo)) | 2499 | if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo)) |
2480 | err = -EINVAL; | 2500 | err = -EINVAL; |
2481 | else { | 2501 | else |
2482 | struct dst_ops *dst_ops = afinfo->dst_ops; | 2502 | RCU_INIT_POINTER(xfrm_policy_afinfo[afinfo->family], |
2483 | xfrm_policy_afinfo[afinfo->family] = NULL; | 2503 | NULL); |
2484 | dst_ops->kmem_cachep = NULL; | 2504 | } |
2485 | dst_ops->check = NULL; | 2505 | spin_unlock(&xfrm_policy_afinfo_lock); |
2486 | dst_ops->negative_advice = NULL; | 2506 | if (!err) { |
2487 | dst_ops->link_failure = NULL; | 2507 | struct dst_ops *dst_ops = afinfo->dst_ops; |
2488 | afinfo->garbage_collect = NULL; | 2508 | |
2489 | } | 2509 | synchronize_rcu(); |
2510 | |||
2511 | dst_ops->kmem_cachep = NULL; | ||
2512 | dst_ops->check = NULL; | ||
2513 | dst_ops->negative_advice = NULL; | ||
2514 | dst_ops->link_failure = NULL; | ||
2515 | afinfo->garbage_collect = NULL; | ||
2490 | } | 2516 | } |
2491 | write_unlock_bh(&xfrm_policy_afinfo_lock); | ||
2492 | return err; | 2517 | return err; |
2493 | } | 2518 | } |
2494 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); | 2519 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); |
@@ -2497,33 +2522,16 @@ static void __net_init xfrm_dst_ops_init(struct net *net) | |||
2497 | { | 2522 | { |
2498 | struct xfrm_policy_afinfo *afinfo; | 2523 | struct xfrm_policy_afinfo *afinfo; |
2499 | 2524 | ||
2500 | read_lock_bh(&xfrm_policy_afinfo_lock); | 2525 | rcu_read_lock(); |
2501 | afinfo = xfrm_policy_afinfo[AF_INET]; | 2526 | afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]); |
2502 | if (afinfo) | 2527 | if (afinfo) |
2503 | net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops; | 2528 | net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops; |
2504 | #if IS_ENABLED(CONFIG_IPV6) | 2529 | #if IS_ENABLED(CONFIG_IPV6) |
2505 | afinfo = xfrm_policy_afinfo[AF_INET6]; | 2530 | afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]); |
2506 | if (afinfo) | 2531 | if (afinfo) |
2507 | net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops; | 2532 | net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops; |
2508 | #endif | 2533 | #endif |
2509 | read_unlock_bh(&xfrm_policy_afinfo_lock); | 2534 | rcu_read_unlock(); |
2510 | } | ||
2511 | |||
2512 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) | ||
2513 | { | ||
2514 | struct xfrm_policy_afinfo *afinfo; | ||
2515 | if (unlikely(family >= NPROTO)) | ||
2516 | return NULL; | ||
2517 | read_lock(&xfrm_policy_afinfo_lock); | ||
2518 | afinfo = xfrm_policy_afinfo[family]; | ||
2519 | if (unlikely(!afinfo)) | ||
2520 | read_unlock(&xfrm_policy_afinfo_lock); | ||
2521 | return afinfo; | ||
2522 | } | ||
2523 | |||
2524 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) | ||
2525 | { | ||
2526 | read_unlock(&xfrm_policy_afinfo_lock); | ||
2527 | } | 2535 | } |
2528 | 2536 | ||
2529 | static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) | 2537 | static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) |
@@ -2630,12 +2638,12 @@ static void xfrm_policy_fini(struct net *net) | |||
2630 | 2638 | ||
2631 | flush_work(&net->xfrm.policy_hash_work); | 2639 | flush_work(&net->xfrm.policy_hash_work); |
2632 | #ifdef CONFIG_XFRM_SUB_POLICY | 2640 | #ifdef CONFIG_XFRM_SUB_POLICY |
2633 | audit_info.loginuid = -1; | 2641 | audit_info.loginuid = INVALID_UID; |
2634 | audit_info.sessionid = -1; | 2642 | audit_info.sessionid = -1; |
2635 | audit_info.secid = 0; | 2643 | audit_info.secid = 0; |
2636 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); | 2644 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); |
2637 | #endif | 2645 | #endif |
2638 | audit_info.loginuid = -1; | 2646 | audit_info.loginuid = INVALID_UID; |
2639 | audit_info.sessionid = -1; | 2647 | audit_info.sessionid = -1; |
2640 | audit_info.secid = 0; | 2648 | audit_info.secid = 0; |
2641 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); | 2649 | xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); |
@@ -2742,7 +2750,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, | |||
2742 | } | 2750 | } |
2743 | 2751 | ||
2744 | void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, | 2752 | void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, |
2745 | uid_t auid, u32 sessionid, u32 secid) | 2753 | kuid_t auid, u32 sessionid, u32 secid) |
2746 | { | 2754 | { |
2747 | struct audit_buffer *audit_buf; | 2755 | struct audit_buffer *audit_buf; |
2748 | 2756 | ||
@@ -2757,7 +2765,7 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, | |||
2757 | EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); | 2765 | EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); |
2758 | 2766 | ||
2759 | void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, | 2767 | void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, |
2760 | uid_t auid, u32 sessionid, u32 secid) | 2768 | kuid_t auid, u32 sessionid, u32 secid) |
2761 | { | 2769 | { |
2762 | struct audit_buffer *audit_buf; | 2770 | struct audit_buffer *audit_buf; |
2763 | 2771 | ||