Skip to content

Commit bab1be7

Browse files
lxindavem330
authored andcommitted
sctp: hold transport before accessing its asoc in sctp_transport_get_next
As Marcelo noticed, in sctp_transport_get_next, it is iterating over transports but then also accessing the association directly, without checking any refcnts before that, which can cause an use-after-free Read. So fix it by holding transport before accessing the association. With that, sctp_transport_hold calls can be removed in the later places. Fixes: 626d16f ("sctp: export some apis or variables for sctp_diag and reuse some for proc") Reported-by: syzbot+fe62a0c9aa6a85c6de16@syzkaller.appspotmail.com Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 050cdc6 commit bab1be7

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

net/sctp/proc.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,6 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
264264
}
265265

266266
transport = (struct sctp_transport *)v;
267-
if (!sctp_transport_hold(transport))
268-
return 0;
269267
assoc = transport->asoc;
270268
epb = &assoc->base;
271269
sk = epb->sk;
@@ -322,8 +320,6 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
322320
}
323321

324322
transport = (struct sctp_transport *)v;
325-
if (!sctp_transport_hold(transport))
326-
return 0;
327323
assoc = transport->asoc;
328324

329325
list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list,

net/sctp/socket.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5005,9 +5005,14 @@ struct sctp_transport *sctp_transport_get_next(struct net *net,
50055005
break;
50065006
}
50075007

5008+
if (!sctp_transport_hold(t))
5009+
continue;
5010+
50085011
if (net_eq(sock_net(t->asoc->base.sk), net) &&
50095012
t->asoc->peer.primary_path == t)
50105013
break;
5014+
5015+
sctp_transport_put(t);
50115016
}
50125017

50135018
return t;
@@ -5017,13 +5022,18 @@ struct sctp_transport *sctp_transport_get_idx(struct net *net,
50175022
struct rhashtable_iter *iter,
50185023
int pos)
50195024
{
5020-
void *obj = SEQ_START_TOKEN;
5025+
struct sctp_transport *t;
50215026

5022-
while (pos && (obj = sctp_transport_get_next(net, iter)) &&
5023-
!IS_ERR(obj))
5024-
pos--;
5027+
if (!pos)
5028+
return SEQ_START_TOKEN;
50255029

5026-
return obj;
5030+
while ((t = sctp_transport_get_next(net, iter)) && !IS_ERR(t)) {
5031+
if (!--pos)
5032+
break;
5033+
sctp_transport_put(t);
5034+
}
5035+
5036+
return t;
50275037
}
50285038

50295039
int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
@@ -5082,8 +5092,6 @@ int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *),
50825092

50835093
tsp = sctp_transport_get_idx(net, &hti, *pos + 1);
50845094
for (; !IS_ERR_OR_NULL(tsp); tsp = sctp_transport_get_next(net, &hti)) {
5085-
if (!sctp_transport_hold(tsp))
5086-
continue;
50875095
ret = cb(tsp, p);
50885096
if (ret)
50895097
break;

0 commit comments

Comments
 (0)