Skip to content

Commit f9d31c4

Browse files
lxindavem330
authored andcommitted
sctp: hold endpoint before calling cb in sctp_transport_lookup_process
The same fix in commit 5ec7d18 ("sctp: use call_rcu to free endpoint") is also needed for dumping one asoc and sock after the lookup. Fixes: 86fdb34 ("sctp: ensure ep is not destroyed before doing the dump") Signed-off-by: Xin Long <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5b40d10 commit f9d31c4

File tree

3 files changed

+37
-34
lines changed

3 files changed

+37
-34
lines changed

include/net/sctp/sctp.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ struct sctp_transport *sctp_transport_get_next(struct net *net,
112112
struct rhashtable_iter *iter);
113113
struct sctp_transport *sctp_transport_get_idx(struct net *net,
114114
struct rhashtable_iter *iter, int pos);
115-
int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
116-
struct net *net,
115+
int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
117116
const union sctp_addr *laddr,
118117
const union sctp_addr *paddr, void *p);
119118
int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,

net/sctp/diag.c

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -245,48 +245,44 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc)
245245
+ 64;
246246
}
247247

248-
static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p)
248+
static int sctp_sock_dump_one(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
249249
{
250250
struct sctp_association *assoc = tsp->asoc;
251-
struct sock *sk = tsp->asoc->base.sk;
252251
struct sctp_comm_param *commp = p;
253-
struct sk_buff *in_skb = commp->skb;
252+
struct sock *sk = ep->base.sk;
254253
const struct inet_diag_req_v2 *req = commp->r;
255-
const struct nlmsghdr *nlh = commp->nlh;
256-
struct net *net = sock_net(in_skb->sk);
254+
struct sk_buff *skb = commp->skb;
257255
struct sk_buff *rep;
258256
int err;
259257

260258
err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
261259
if (err)
262-
goto out;
260+
return err;
263261

264-
err = -ENOMEM;
265262
rep = nlmsg_new(inet_assoc_attr_size(assoc), GFP_KERNEL);
266263
if (!rep)
267-
goto out;
264+
return -ENOMEM;
268265

269266
lock_sock(sk);
270-
if (sk != assoc->base.sk) {
271-
release_sock(sk);
272-
sk = assoc->base.sk;
273-
lock_sock(sk);
267+
if (ep != assoc->ep) {
268+
err = -EAGAIN;
269+
goto out;
274270
}
275-
err = inet_sctp_diag_fill(sk, assoc, rep, req,
276-
sk_user_ns(NETLINK_CB(in_skb).sk),
277-
NETLINK_CB(in_skb).portid,
278-
nlh->nlmsg_seq, 0, nlh,
279-
commp->net_admin);
280-
release_sock(sk);
271+
272+
err = inet_sctp_diag_fill(sk, assoc, rep, req, sk_user_ns(NETLINK_CB(skb).sk),
273+
NETLINK_CB(skb).portid, commp->nlh->nlmsg_seq, 0,
274+
commp->nlh, commp->net_admin);
281275
if (err < 0) {
282276
WARN_ON(err == -EMSGSIZE);
283-
kfree_skb(rep);
284277
goto out;
285278
}
279+
release_sock(sk);
286280

287-
err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
281+
return nlmsg_unicast(sock_net(skb->sk)->diag_nlsk, rep, NETLINK_CB(skb).portid);
288282

289283
out:
284+
release_sock(sk);
285+
kfree_skb(rep);
290286
return err;
291287
}
292288

@@ -429,15 +425,15 @@ static void sctp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
429425
static int sctp_diag_dump_one(struct netlink_callback *cb,
430426
const struct inet_diag_req_v2 *req)
431427
{
432-
struct sk_buff *in_skb = cb->skb;
433-
struct net *net = sock_net(in_skb->sk);
428+
struct sk_buff *skb = cb->skb;
429+
struct net *net = sock_net(skb->sk);
434430
const struct nlmsghdr *nlh = cb->nlh;
435431
union sctp_addr laddr, paddr;
436432
struct sctp_comm_param commp = {
437-
.skb = in_skb,
433+
.skb = skb,
438434
.r = req,
439435
.nlh = nlh,
440-
.net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN),
436+
.net_admin = netlink_net_capable(skb, CAP_NET_ADMIN),
441437
};
442438

443439
if (req->sdiag_family == AF_INET) {
@@ -460,7 +456,7 @@ static int sctp_diag_dump_one(struct netlink_callback *cb,
460456
paddr.v6.sin6_family = AF_INET6;
461457
}
462458

463-
return sctp_transport_lookup_process(sctp_tsp_dump_one,
459+
return sctp_transport_lookup_process(sctp_sock_dump_one,
464460
net, &laddr, &paddr, &commp);
465461
}
466462

net/sctp/socket.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5317,23 +5317,31 @@ int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
53175317
}
53185318
EXPORT_SYMBOL_GPL(sctp_for_each_endpoint);
53195319

5320-
int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
5321-
struct net *net,
5320+
int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
53225321
const union sctp_addr *laddr,
53235322
const union sctp_addr *paddr, void *p)
53245323
{
53255324
struct sctp_transport *transport;
5326-
int err;
5325+
struct sctp_endpoint *ep;
5326+
int err = -ENOENT;
53275327

53285328
rcu_read_lock();
53295329
transport = sctp_addrs_lookup_transport(net, laddr, paddr);
5330+
if (!transport) {
5331+
rcu_read_unlock();
5332+
return err;
5333+
}
5334+
ep = transport->asoc->ep;
5335+
if (!sctp_endpoint_hold(ep)) { /* asoc can be peeled off */
5336+
sctp_transport_put(transport);
5337+
rcu_read_unlock();
5338+
return err;
5339+
}
53305340
rcu_read_unlock();
5331-
if (!transport)
5332-
return -ENOENT;
53335341

5334-
err = cb(transport, p);
5342+
err = cb(ep, transport, p);
5343+
sctp_endpoint_put(ep);
53355344
sctp_transport_put(transport);
5336-
53375345
return err;
53385346
}
53395347
EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);

0 commit comments

Comments
 (0)