|
@@ -1488,11 +1488,16 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
|
|
|
* treat the second attempt as a no-op instead of returning
|
|
|
* an error.
|
|
|
*/
|
|
|
- if (help && help->helper &&
|
|
|
- !strcmp(help->helper->name, helpname))
|
|
|
- return 0;
|
|
|
- else
|
|
|
- return -EBUSY;
|
|
|
+ err = -EBUSY;
|
|
|
+ if (help) {
|
|
|
+ rcu_read_lock();
|
|
|
+ helper = rcu_dereference(help->helper);
|
|
|
+ if (helper && !strcmp(helper->name, helpname))
|
|
|
+ err = 0;
|
|
|
+ rcu_read_unlock();
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
if (!strcmp(helpname, "")) {
|
|
@@ -1929,9 +1934,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
|
|
|
|
|
|
err = 0;
|
|
|
if (test_bit(IPS_EXPECTED_BIT, &ct->status))
|
|
|
- events = IPCT_RELATED;
|
|
|
+ events = 1 << IPCT_RELATED;
|
|
|
else
|
|
|
- events = IPCT_NEW;
|
|
|
+ events = 1 << IPCT_NEW;
|
|
|
|
|
|
if (cda[CTA_LABELS] &&
|
|
|
ctnetlink_attach_labels(ct, cda) == 0)
|
|
@@ -2675,8 +2680,8 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
last = (struct nf_conntrack_expect *)cb->args[1];
|
|
|
for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
|
|
|
restart:
|
|
|
- hlist_for_each_entry(exp, &nf_ct_expect_hash[cb->args[0]],
|
|
|
- hnode) {
|
|
|
+ hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
|
|
|
+ hnode) {
|
|
|
if (l3proto && exp->tuple.src.l3num != l3proto)
|
|
|
continue;
|
|
|
|
|
@@ -2727,7 +2732,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
rcu_read_lock();
|
|
|
last = (struct nf_conntrack_expect *)cb->args[1];
|
|
|
restart:
|
|
|
- hlist_for_each_entry(exp, &help->expectations, lnode) {
|
|
|
+ hlist_for_each_entry_rcu(exp, &help->expectations, lnode) {
|
|
|
if (l3proto && exp->tuple.src.l3num != l3proto)
|
|
|
continue;
|
|
|
if (cb->args[1]) {
|
|
@@ -2789,6 +2794,12 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
|
|
|
return -ENOENT;
|
|
|
|
|
|
ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
+ /* No expectation linked to this connection tracking. */
|
|
|
+ if (!nfct_help(ct)) {
|
|
|
+ nf_ct_put(ct);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
c.data = ct;
|
|
|
|
|
|
err = netlink_dump_start(ctnl, skb, nlh, &c);
|
|
@@ -3133,23 +3144,27 @@ ctnetlink_create_expect(struct net *net,
|
|
|
return -ENOENT;
|
|
|
ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
|
|
|
+ rcu_read_lock();
|
|
|
if (cda[CTA_EXPECT_HELP_NAME]) {
|
|
|
const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
|
|
|
|
|
|
helper = __nf_conntrack_helper_find(helpname, u3,
|
|
|
nf_ct_protonum(ct));
|
|
|
if (helper == NULL) {
|
|
|
+ rcu_read_unlock();
|
|
|
#ifdef CONFIG_MODULES
|
|
|
if (request_module("nfct-helper-%s", helpname) < 0) {
|
|
|
err = -EOPNOTSUPP;
|
|
|
goto err_ct;
|
|
|
}
|
|
|
+ rcu_read_lock();
|
|
|
helper = __nf_conntrack_helper_find(helpname, u3,
|
|
|
nf_ct_protonum(ct));
|
|
|
if (helper) {
|
|
|
err = -EAGAIN;
|
|
|
- goto err_ct;
|
|
|
+ goto err_rcu;
|
|
|
}
|
|
|
+ rcu_read_unlock();
|
|
|
#endif
|
|
|
err = -EOPNOTSUPP;
|
|
|
goto err_ct;
|
|
@@ -3159,11 +3174,13 @@ ctnetlink_create_expect(struct net *net,
|
|
|
exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
|
|
|
if (IS_ERR(exp)) {
|
|
|
err = PTR_ERR(exp);
|
|
|
- goto err_ct;
|
|
|
+ goto err_rcu;
|
|
|
}
|
|
|
|
|
|
err = nf_ct_expect_related_report(exp, portid, report);
|
|
|
nf_ct_expect_put(exp);
|
|
|
+err_rcu:
|
|
|
+ rcu_read_unlock();
|
|
|
err_ct:
|
|
|
nf_ct_put(ct);
|
|
|
return err;
|