aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2018-02-06 05:39:32 -0500
committerDaniel Borkmann <daniel@iogearbox.net>2018-02-06 05:39:33 -0500
commit41b0530eca69740f0c69eb5a867c41b01ec2e551 (patch)
tree07ee2d1dc8963140d2e718a8600112892c8add3f /net
parent7b4eb53d95c30bdc55c44647c6968f24227fd1ba (diff)
parent3d9e952697de89b53227f06d4241f275eb99cfc4 (diff)
Merge branch 'bpf-sockmap-fixes'
John Fastabend says: ==================== A set of fixes for sockmap to resolve programs referencing sockmaps and closing without deleting all entries in the map and/or not detaching BPF programs attached to the map. Both leaving entries in the map and not detaching programs may result in the map failing to be removed by BPF infrastructure due to reference counts never reaching zero. For this we pull in the ULP infrastructure to hook into the close() hook of the sock layer. This seemed natural because we have additional sockmap features (to add support for TX hooks) that will also use the ULP infrastructure. This allows us to cleanup entries in the map when socks are closed() and avoid trying to get the sk_state_change() hook to fire in all cases. The second issue resolved here occurs when users don't detach programs. The gist is a refcnt issue resolved by implementing the release callback. See patch for details. For testing I ran both sample/sockmap and selftests bpf/test_maps.c. Dave Watson ran TLS test suite on v1 version of the patches without the put_module error path change. v4 fix missing rcu_unlock() v3 wrap psock reference in RCU v2 changes rebased onto bpf-next with small update adding module_put ==================== Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_ulp.c59
-rw-r--r--net/tls/tls_main.c2
2 files changed, 56 insertions, 5 deletions
diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c
index 6bb9e14c710a..622caa4039e0 100644
--- a/net/ipv4/tcp_ulp.c
+++ b/net/ipv4/tcp_ulp.c
@@ -29,6 +29,18 @@ static struct tcp_ulp_ops *tcp_ulp_find(const char *name)
29 return NULL; 29 return NULL;
30} 30}
31 31
32static struct tcp_ulp_ops *tcp_ulp_find_id(const int ulp)
33{
34 struct tcp_ulp_ops *e;
35
36 list_for_each_entry_rcu(e, &tcp_ulp_list, list) {
37 if (e->uid == ulp)
38 return e;
39 }
40
41 return NULL;
42}
43
32static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) 44static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
33{ 45{
34 const struct tcp_ulp_ops *ulp = NULL; 46 const struct tcp_ulp_ops *ulp = NULL;
@@ -51,6 +63,18 @@ static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
51 return ulp; 63 return ulp;
52} 64}
53 65
66static const struct tcp_ulp_ops *__tcp_ulp_lookup(const int uid)
67{
68 const struct tcp_ulp_ops *ulp;
69
70 rcu_read_lock();
71 ulp = tcp_ulp_find_id(uid);
72 if (!ulp || !try_module_get(ulp->owner))
73 ulp = NULL;
74 rcu_read_unlock();
75 return ulp;
76}
77
54/* Attach new upper layer protocol to the list 78/* Attach new upper layer protocol to the list
55 * of available protocols. 79 * of available protocols.
56 */ 80 */
@@ -59,13 +83,10 @@ int tcp_register_ulp(struct tcp_ulp_ops *ulp)
59 int ret = 0; 83 int ret = 0;
60 84
61 spin_lock(&tcp_ulp_list_lock); 85 spin_lock(&tcp_ulp_list_lock);
62 if (tcp_ulp_find(ulp->name)) { 86 if (tcp_ulp_find(ulp->name))
63 pr_notice("%s already registered or non-unique name\n",
64 ulp->name);
65 ret = -EEXIST; 87 ret = -EEXIST;
66 } else { 88 else
67 list_add_tail_rcu(&ulp->list, &tcp_ulp_list); 89 list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
68 }
69 spin_unlock(&tcp_ulp_list_lock); 90 spin_unlock(&tcp_ulp_list_lock);
70 91
71 return ret; 92 return ret;
@@ -124,6 +145,34 @@ int tcp_set_ulp(struct sock *sk, const char *name)
124 if (!ulp_ops) 145 if (!ulp_ops)
125 return -ENOENT; 146 return -ENOENT;
126 147
148 if (!ulp_ops->user_visible) {
149 module_put(ulp_ops->owner);
150 return -ENOENT;
151 }
152
153 err = ulp_ops->init(sk);
154 if (err) {
155 module_put(ulp_ops->owner);
156 return err;
157 }
158
159 icsk->icsk_ulp_ops = ulp_ops;
160 return 0;
161}
162
163int tcp_set_ulp_id(struct sock *sk, int ulp)
164{
165 struct inet_connection_sock *icsk = inet_csk(sk);
166 const struct tcp_ulp_ops *ulp_ops;
167 int err;
168
169 if (icsk->icsk_ulp_ops)
170 return -EEXIST;
171
172 ulp_ops = __tcp_ulp_lookup(ulp);
173 if (!ulp_ops)
174 return -ENOENT;
175
127 err = ulp_ops->init(sk); 176 err = ulp_ops->init(sk);
128 if (err) { 177 if (err) {
129 module_put(ulp_ops->owner); 178 module_put(ulp_ops->owner);
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 736719c8314e..b0d5fcea47e7 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -484,6 +484,8 @@ out:
484 484
485static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = { 485static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
486 .name = "tls", 486 .name = "tls",
487 .uid = TCP_ULP_TLS,
488 .user_visible = true,
487 .owner = THIS_MODULE, 489 .owner = THIS_MODULE,
488 .init = tls_init, 490 .init = tls_init,
489}; 491};