...
...
57
where the external address is advertised and multiple connections
57
where the external address is advertised and multiple connections
58
already exist, multiple subflow SYNs arrive in parallel which tends to
58
already exist, multiple subflow SYNs arrive in parallel which tends to
59
trigger the race during creation of the first local_addr_list entries
59
trigger the race during creation of the first local_addr_list entries
60
which have the internal address instead.
60
which have the internal address instead.
61
61
62
Fix this problem by switching mptcp_pm_nl_append_new_local_addr to use
62
Fix by skipping the replacement of an existing implicit local address if
63
call_rcu . As part of plumbing this up, make
63
called via mptcp_pm_nl_get_local_id.
64
__mptcp_pm_release_addr_entry take a rcu_head which is used by all
65
callers regardless of cleanup method.
66
64
67
Cc: stable@vger.kernel.org
65
Cc: stable@vger.kernel.org
68
Fixes: d045b9eb95a9 ("mptcp: introduce implicit endpoints")
66
Fixes: d045b9eb95a9 ("mptcp: introduce implicit endpoints")
67
Suggested-by: Paolo Abeni <pabeni@redhat.com>
69
Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
68
Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
70
---
69
---
71
net/mptcp/pm_netlink.c | 19 ++++++++++++-------
70
v2:
72
net/mptcp/protocol.h | 1 +
71
- Switch from call_rcu to skipping replacement if invoked via
73
2 files changed, 13 insertions(+), 7 deletions(-)
72
mptcp_pm_nl_get_local_id. (Feedback from Paolo Abeni)
73
---
74
net/mptcp/pm_netlink.c | 18 +++++++++++++++---
75
1 file changed, 15 insertions(+), 3 deletions(-)
74
76
75
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
77
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
76
index XXXXXXX..XXXXXXX 100644
78
index XXXXXXX..XXXXXXX 100644
77
--- a/net/mptcp/pm_netlink.c
79
--- a/net/mptcp/pm_netlink.c
78
+++ b/net/mptcp/pm_netlink.c
80
+++ b/net/mptcp/pm_netlink.c
79
@@ -XXX,XX +XXX,XX @@ static bool address_use_port(struct mptcp_pm_addr_entry *entry)
81
@@ -XXX,XX +XXX,XX @@ static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
80
        MPTCP_PM_ADDR_FLAG_SIGNAL;
82
81
}
83
static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
82
84
                     struct mptcp_pm_addr_entry *entry,
83
-/* caller must ensure the RCU grace period is already elapsed */
85
-                     bool needs_id)
84
-static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
86
+                     bool needs_id, bool replace)
85
+/*
86
+ * Caller must ensure the RCU grace period is already elapsed or call this
87
+ * via a RCU callback.
88
+ */
89
+static void __mptcp_pm_release_addr_entry(struct rcu_head *head)
90
{
87
{
91
+    struct mptcp_pm_addr_entry *entry;
88
    struct mptcp_pm_addr_entry *cur, *del_entry = NULL;
89
    unsigned int addr_max;
90
@@ -XXX,XX +XXX,XX @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
91
            if (entry->addr.id)
92
                goto out;
93
94
+            /* allow callers that only need to look up the local
95
+             * addr's id to skip replacement. This allows them to
96
+             * avoid calling synchronize_rcu in the packet recv
97
+             * path.
98
+             */
99
+            if (!replace) {
100
+                kfree(entry);
101
+                ret = cur->addr.id;
102
+                goto out;
103
+            }
92
+
104
+
93
+    entry = container_of(head, struct mptcp_pm_addr_entry, rcu_head);
105
            pernet->addrs--;
94
    if (entry->lsk)
106
            entry->addr.id = cur->addr.id;
95
        sock_release(entry->lsk);
107
            list_del_rcu(&cur->list);
96
    kfree(entry);
108
@@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc
97
@@ -XXX,XX +XXX,XX @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
109
    entry->ifindex = 0;
98
110
    entry->flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
99
    /* just replaced an existing entry, free it */
111
    entry->lsk = NULL;
100
    if (del_entry) {
112
-    ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true);
101
-        synchronize_rcu();
113
+    ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true, false);
102
-        __mptcp_pm_release_addr_entry(del_entry);
114
    if (ret < 0)
103
+        call_rcu(&del_entry->rcu_head, __mptcp_pm_release_addr_entry);
115
        kfree(entry);
116
117
@@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
118
        }
104
    }
119
    }
105
    return ret;
120
    ret = mptcp_pm_nl_append_new_local_addr(pernet, entry,
106
}
121
-                        !mptcp_pm_has_addr_attr_id(attr, info));
107
@@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
122
+                        !mptcp_pm_has_addr_attr_id(attr, info),
108
    return 0;
123
+                        true);
109
124
    if (ret < 0) {
110
out_free:
125
        GENL_SET_ERR_MSG_FMT(info, "too many addresses or duplicate one: %d", ret);
111
-    __mptcp_pm_release_addr_entry(entry);
126
        goto out_free;
112
+    __mptcp_pm_release_addr_entry(&entry->rcu_head);
127
113
    return ret;
128
base-commit: 384fa1d90d092d36bfe13c0473194120ce28a50e
114
}
115
116
@@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_del_addr_doit(struct sk_buff *skb, struct genl_info *info)
117
118
    mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), entry);
119
    synchronize_rcu();
120
-    __mptcp_pm_release_addr_entry(entry);
121
+    __mptcp_pm_release_addr_entry(&entry->rcu_head);
122
123
    return ret;
124
}
125
@@ -XXX,XX +XXX,XX @@ static void __flush_addrs(struct list_head *list)
126
        cur = list_entry(list->next,
127
                 struct mptcp_pm_addr_entry, list);
128
        list_del_rcu(&cur->list);
129
-        __mptcp_pm_release_addr_entry(cur);
130
+        __mptcp_pm_release_addr_entry(&cur->rcu_head);
131
    }
132
}
133
134
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
135
index XXXXXXX..XXXXXXX 100644
136
--- a/net/mptcp/protocol.h
137
+++ b/net/mptcp/protocol.h
138
@@ -XXX,XX +XXX,XX @@ struct mptcp_pm_addr_entry {
139
    u8            flags;
140
    int            ifindex;
141
    struct socket        *lsk;
142
+    struct rcu_head        rcu_head;
143
};
144
145
struct mptcp_data_frag {
146
--
129
--
147
2.25.1
130
2.25.1
diff view generated by jsdifflib