diff options
Diffstat (limited to 'net/netfilter/nf_conntrack_netlink.c')
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index d6d39e24132..3f73327794a 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 | ||