diff options
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 13 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 9 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 26 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 4 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 34 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_gre.c | 2 |
7 files changed, 61 insertions, 29 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index fd62a41d69cc..6dc72a815f77 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -133,6 +133,7 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum, | |||
133 | struct nf_conn *ct; | 133 | struct nf_conn *ct; |
134 | enum ip_conntrack_info ctinfo; | 134 | enum ip_conntrack_info ctinfo; |
135 | struct nf_conn_help *help; | 135 | struct nf_conn_help *help; |
136 | struct nf_conntrack_helper *helper; | ||
136 | 137 | ||
137 | /* This is where we call the helper: as the packet goes out. */ | 138 | /* This is where we call the helper: as the packet goes out. */ |
138 | ct = nf_ct_get(*pskb, &ctinfo); | 139 | ct = nf_ct_get(*pskb, &ctinfo); |
@@ -140,12 +141,14 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum, | |||
140 | return NF_ACCEPT; | 141 | return NF_ACCEPT; |
141 | 142 | ||
142 | help = nfct_help(ct); | 143 | help = nfct_help(ct); |
143 | if (!help || !help->helper) | 144 | if (!help) |
144 | return NF_ACCEPT; | 145 | return NF_ACCEPT; |
145 | 146 | /* rcu_read_lock()ed by nf_hook_slow */ | |
146 | return help->helper->help(pskb, | 147 | helper = rcu_dereference(help->helper); |
147 | skb_network_offset(*pskb) + ip_hdrlen(*pskb), | 148 | if (!helper) |
148 | ct, ctinfo); | 149 | return NF_ACCEPT; |
150 | return helper->help(pskb, skb_network_offset(*pskb) + ip_hdrlen(*pskb), | ||
151 | ct, ctinfo); | ||
149 | } | 152 | } |
150 | 153 | ||
151 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | 154 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index dc442fb791b0..1b1797f1f33d 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -160,6 +160,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
160 | { | 160 | { |
161 | struct nf_conn *ct; | 161 | struct nf_conn *ct; |
162 | struct nf_conn_help *help; | 162 | struct nf_conn_help *help; |
163 | struct nf_conntrack_helper *helper; | ||
163 | enum ip_conntrack_info ctinfo; | 164 | enum ip_conntrack_info ctinfo; |
164 | unsigned int ret, protoff; | 165 | unsigned int ret, protoff; |
165 | unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data; | 166 | unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data; |
@@ -172,7 +173,11 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
172 | goto out; | 173 | goto out; |
173 | 174 | ||
174 | help = nfct_help(ct); | 175 | help = nfct_help(ct); |
175 | if (!help || !help->helper) | 176 | if (!help) |
177 | goto out; | ||
178 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
179 | helper = rcu_dereference(help->helper); | ||
180 | if (!helper) | ||
176 | goto out; | 181 | goto out; |
177 | 182 | ||
178 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | 183 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, |
@@ -182,7 +187,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
182 | return NF_ACCEPT; | 187 | return NF_ACCEPT; |
183 | } | 188 | } |
184 | 189 | ||
185 | ret = help->helper->help(pskb, protoff, ct, ctinfo); | 190 | ret = helper->help(pskb, protoff, ct, ctinfo); |
186 | if (ret != NF_ACCEPT) | 191 | if (ret != NF_ACCEPT) |
187 | return ret; | 192 | return ret; |
188 | out: | 193 | out: |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 483e927a9ca4..7a15e30356f2 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -350,9 +350,15 @@ static void death_by_timeout(unsigned long ul_conntrack) | |||
350 | { | 350 | { |
351 | struct nf_conn *ct = (void *)ul_conntrack; | 351 | struct nf_conn *ct = (void *)ul_conntrack; |
352 | struct nf_conn_help *help = nfct_help(ct); | 352 | struct nf_conn_help *help = nfct_help(ct); |
353 | struct nf_conntrack_helper *helper; | ||
353 | 354 | ||
354 | if (help && help->helper && help->helper->destroy) | 355 | if (help) { |
355 | help->helper->destroy(ct); | 356 | rcu_read_lock(); |
357 | helper = rcu_dereference(help->helper); | ||
358 | if (helper && helper->destroy) | ||
359 | helper->destroy(ct); | ||
360 | rcu_read_unlock(); | ||
361 | } | ||
356 | 362 | ||
357 | write_lock_bh(&nf_conntrack_lock); | 363 | write_lock_bh(&nf_conntrack_lock); |
358 | /* Inside lock so preempt is disabled on module removal path. | 364 | /* Inside lock so preempt is disabled on module removal path. |
@@ -661,6 +667,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
661 | unsigned int dataoff) | 667 | unsigned int dataoff) |
662 | { | 668 | { |
663 | struct nf_conn *conntrack; | 669 | struct nf_conn *conntrack; |
670 | struct nf_conn_help *help; | ||
664 | struct nf_conntrack_tuple repl_tuple; | 671 | struct nf_conntrack_tuple repl_tuple; |
665 | struct nf_conntrack_expect *exp; | 672 | struct nf_conntrack_expect *exp; |
666 | u_int32_t features = 0; | 673 | u_int32_t features = 0; |
@@ -691,6 +698,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
691 | write_lock_bh(&nf_conntrack_lock); | 698 | write_lock_bh(&nf_conntrack_lock); |
692 | exp = find_expectation(tuple); | 699 | exp = find_expectation(tuple); |
693 | 700 | ||
701 | help = nfct_help(conntrack); | ||
694 | if (exp) { | 702 | if (exp) { |
695 | DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | 703 | DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", |
696 | conntrack, exp); | 704 | conntrack, exp); |
@@ -698,7 +706,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
698 | __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | 706 | __set_bit(IPS_EXPECTED_BIT, &conntrack->status); |
699 | conntrack->master = exp->master; | 707 | conntrack->master = exp->master; |
700 | if (exp->helper) | 708 | if (exp->helper) |
701 | nfct_help(conntrack)->helper = exp->helper; | 709 | rcu_assign_pointer(help->helper, exp->helper); |
702 | #ifdef CONFIG_NF_CONNTRACK_MARK | 710 | #ifdef CONFIG_NF_CONNTRACK_MARK |
703 | conntrack->mark = exp->master->mark; | 711 | conntrack->mark = exp->master->mark; |
704 | #endif | 712 | #endif |
@@ -708,10 +716,11 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
708 | nf_conntrack_get(&conntrack->master->ct_general); | 716 | nf_conntrack_get(&conntrack->master->ct_general); |
709 | NF_CT_STAT_INC(expect_new); | 717 | NF_CT_STAT_INC(expect_new); |
710 | } else { | 718 | } else { |
711 | struct nf_conn_help *help = nfct_help(conntrack); | 719 | if (help) { |
712 | 720 | /* not in hash table yet, so not strictly necessary */ | |
713 | if (help) | 721 | rcu_assign_pointer(help->helper, |
714 | help->helper = __nf_ct_helper_find(&repl_tuple); | 722 | __nf_ct_helper_find(&repl_tuple)); |
723 | } | ||
715 | NF_CT_STAT_INC(new); | 724 | NF_CT_STAT_INC(new); |
716 | } | 725 | } |
717 | 726 | ||
@@ -893,7 +902,8 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, | |||
893 | helper = __nf_ct_helper_find(newreply); | 902 | helper = __nf_ct_helper_find(newreply); |
894 | if (helper) | 903 | if (helper) |
895 | memset(&help->help, 0, sizeof(help->help)); | 904 | memset(&help->help, 0, sizeof(help->help)); |
896 | help->helper = helper; | 905 | /* not in hash table yet, so not strictly necessary */ |
906 | rcu_assign_pointer(help->helper, helper); | ||
897 | } | 907 | } |
898 | write_unlock_bh(&nf_conntrack_lock); | 908 | write_unlock_bh(&nf_conntrack_lock); |
899 | } | 909 | } |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 117cbfdb910c..504fb6c083f9 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -337,6 +337,10 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | |||
337 | NF_CT_ASSERT(master_help); | 337 | NF_CT_ASSERT(master_help); |
338 | 338 | ||
339 | write_lock_bh(&nf_conntrack_lock); | 339 | write_lock_bh(&nf_conntrack_lock); |
340 | if (!master_help->helper) { | ||
341 | ret = -ESHUTDOWN; | ||
342 | goto out; | ||
343 | } | ||
340 | list_for_each_entry(i, &nf_conntrack_expect_list, list) { | 344 | list_for_each_entry(i, &nf_conntrack_expect_list, list) { |
341 | if (expect_matches(i, expect)) { | 345 | if (expect_matches(i, expect)) { |
342 | /* Refresh timer: if it's dying, ignore.. */ | 346 | /* Refresh timer: if it's dying, ignore.. */ |
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 0743be4434b0..f868b7fbd9b4 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -93,7 +93,7 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, | |||
93 | 93 | ||
94 | if (help && help->helper == me) { | 94 | if (help && help->helper == me) { |
95 | nf_conntrack_event(IPCT_HELPER, ct); | 95 | nf_conntrack_event(IPCT_HELPER, ct); |
96 | help->helper = NULL; | 96 | rcu_assign_pointer(help->helper, NULL); |
97 | } | 97 | } |
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index d6d39e241327..3f73327794ab 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -171,21 +171,29 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) | |||
171 | { | 171 | { |
172 | struct nfattr *nest_helper; | 172 | struct nfattr *nest_helper; |
173 | const struct nf_conn_help *help = nfct_help(ct); | 173 | const struct nf_conn_help *help = nfct_help(ct); |
174 | struct nf_conntrack_helper *helper; | ||
174 | 175 | ||
175 | if (!help || !help->helper) | 176 | if (!help) |
176 | return 0; | 177 | return 0; |
177 | 178 | ||
179 | rcu_read_lock(); | ||
180 | helper = rcu_dereference(help->helper); | ||
181 | if (!helper) | ||
182 | goto out; | ||
183 | |||
178 | nest_helper = NFA_NEST(skb, CTA_HELP); | 184 | nest_helper = NFA_NEST(skb, CTA_HELP); |
179 | NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name); | 185 | NFA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); |
180 | 186 | ||
181 | if (help->helper->to_nfattr) | 187 | if (helper->to_nfattr) |
182 | help->helper->to_nfattr(skb, ct); | 188 | helper->to_nfattr(skb, ct); |
183 | 189 | ||
184 | NFA_NEST_END(skb, nest_helper); | 190 | NFA_NEST_END(skb, nest_helper); |
185 | 191 | out: | |
192 | rcu_read_unlock(); | ||
186 | return 0; | 193 | return 0; |
187 | 194 | ||
188 | nfattr_failure: | 195 | nfattr_failure: |
196 | rcu_read_unlock(); | ||
189 | return -1; | 197 | return -1; |
190 | } | 198 | } |
191 | 199 | ||
@@ -842,7 +850,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
842 | if (help && help->helper) { | 850 | if (help && help->helper) { |
843 | /* we had a helper before ... */ | 851 | /* we had a helper before ... */ |
844 | nf_ct_remove_expectations(ct); | 852 | nf_ct_remove_expectations(ct); |
845 | help->helper = NULL; | 853 | rcu_assign_pointer(help->helper, NULL); |
846 | } | 854 | } |
847 | 855 | ||
848 | return 0; | 856 | return 0; |
@@ -866,7 +874,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
866 | 874 | ||
867 | /* need to zero data of old helper */ | 875 | /* need to zero data of old helper */ |
868 | memset(&help->help, 0, sizeof(help->help)); | 876 | memset(&help->help, 0, sizeof(help->help)); |
869 | help->helper = helper; | 877 | rcu_assign_pointer(help->helper, helper); |
870 | 878 | ||
871 | return 0; | 879 | return 0; |
872 | } | 880 | } |
@@ -950,6 +958,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
950 | struct nf_conn *ct; | 958 | struct nf_conn *ct; |
951 | int err = -EINVAL; | 959 | int err = -EINVAL; |
952 | struct nf_conn_help *help; | 960 | struct nf_conn_help *help; |
961 | struct nf_conntrack_helper *helper = NULL; | ||
953 | 962 | ||
954 | ct = nf_conntrack_alloc(otuple, rtuple); | 963 | ct = nf_conntrack_alloc(otuple, rtuple); |
955 | if (ct == NULL || IS_ERR(ct)) | 964 | if (ct == NULL || IS_ERR(ct)) |
@@ -980,14 +989,17 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
980 | #endif | 989 | #endif |
981 | 990 | ||
982 | help = nfct_help(ct); | 991 | help = nfct_help(ct); |
983 | if (help) | 992 | if (help) { |
984 | help->helper = nf_ct_helper_find_get(rtuple); | 993 | helper = nf_ct_helper_find_get(rtuple); |
994 | /* not in hash table yet so not strictly necessary */ | ||
995 | rcu_assign_pointer(help->helper, helper); | ||
996 | } | ||
985 | 997 | ||
986 | add_timer(&ct->timeout); | 998 | add_timer(&ct->timeout); |
987 | nf_conntrack_hash_insert(ct); | 999 | nf_conntrack_hash_insert(ct); |
988 | 1000 | ||
989 | if (help && help->helper) | 1001 | if (helper) |
990 | nf_ct_helper_put(help->helper); | 1002 | nf_ct_helper_put(helper); |
991 | 1003 | ||
992 | return 0; | 1004 | return 0; |
993 | 1005 | ||
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 5434472420fe..339c397d1b5f 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -100,7 +100,6 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, | |||
100 | struct nf_conn_help *help = nfct_help(ct); | 100 | struct nf_conn_help *help = nfct_help(ct); |
101 | struct nf_ct_gre_keymap **kmp, *km; | 101 | struct nf_ct_gre_keymap **kmp, *km; |
102 | 102 | ||
103 | BUG_ON(strcmp(help->helper->name, "pptp")); | ||
104 | kmp = &help->help.ct_pptp_info.keymap[dir]; | 103 | kmp = &help->help.ct_pptp_info.keymap[dir]; |
105 | if (*kmp) { | 104 | if (*kmp) { |
106 | /* check whether it's a retransmission */ | 105 | /* check whether it's a retransmission */ |
@@ -137,7 +136,6 @@ void nf_ct_gre_keymap_destroy(struct nf_conn *ct) | |||
137 | enum ip_conntrack_dir dir; | 136 | enum ip_conntrack_dir dir; |
138 | 137 | ||
139 | DEBUGP("entering for ct %p\n", ct); | 138 | DEBUGP("entering for ct %p\n", ct); |
140 | BUG_ON(strcmp(help->helper->name, "pptp")); | ||
141 | 139 | ||
142 | write_lock_bh(&nf_ct_gre_lock); | 140 | write_lock_bh(&nf_ct_gre_lock); |
143 | for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { | 141 | for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { |