Skip to content

Commit 9ed7bfc

Browse files
zhengchaoshaokuba-moo
authored andcommitted
sctp: fix memory leak in sctp_stream_outq_migrate()
When sctp_stream_outq_migrate() is called to release stream out resources, the memory pointed to by prio_head in stream out is not released. The memory leak information is as follows: unreferenced object 0xffff88801fe79f80 (size 64): comm "sctp_repo", pid 7957, jiffies 4294951704 (age 36.480s) hex dump (first 32 bytes): 80 9f e7 1f 80 88 ff ff 80 9f e7 1f 80 88 ff ff ................ 90 9f e7 1f 80 88 ff ff 90 9f e7 1f 80 88 ff ff ................ backtrace: [<ffffffff81b215c6>] kmalloc_trace+0x26/0x60 [<ffffffff88ae517c>] sctp_sched_prio_set+0x4cc/0x770 [<ffffffff88ad64f2>] sctp_stream_init_ext+0xd2/0x1b0 [<ffffffff88aa2604>] sctp_sendmsg_to_asoc+0x1614/0x1a30 [<ffffffff88ab7ff1>] sctp_sendmsg+0xda1/0x1ef0 [<ffffffff87f765ed>] inet_sendmsg+0x9d/0xe0 [<ffffffff8754b5b3>] sock_sendmsg+0xd3/0x120 [<ffffffff8755446a>] __sys_sendto+0x23a/0x340 [<ffffffff87554651>] __x64_sys_sendto+0xe1/0x1b0 [<ffffffff89978b49>] do_syscall_64+0x39/0xb0 [<ffffffff89a0008b>] entry_SYSCALL_64_after_hwframe+0x63/0xcd Link: https://syzkaller.appspot.com/bug?exrid=29c402e56c4760763cc0 Fixes: 637784a ("sctp: introduce priority based stream scheduler") Reported-by: [email protected] Signed-off-by: Zhengchao Shao <[email protected]> Reviewed-by: Xin Long <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent b85f628 commit 9ed7bfc

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-7
lines changed

include/net/sctp/stream_sched.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ struct sctp_sched_ops {
2626
int (*init)(struct sctp_stream *stream);
2727
/* Init a stream */
2828
int (*init_sid)(struct sctp_stream *stream, __u16 sid, gfp_t gfp);
29+
/* free a stream */
30+
void (*free_sid)(struct sctp_stream *stream, __u16 sid);
2931
/* Frees the entire thing */
3032
void (*free)(struct sctp_stream *stream);
3133

net/sctp/stream.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,19 @@ static void sctp_stream_shrink_out(struct sctp_stream *stream, __u16 outcnt)
5252
}
5353
}
5454

55+
static void sctp_stream_free_ext(struct sctp_stream *stream, __u16 sid)
56+
{
57+
struct sctp_sched_ops *sched;
58+
59+
if (!SCTP_SO(stream, sid)->ext)
60+
return;
61+
62+
sched = sctp_sched_ops_from_stream(stream);
63+
sched->free_sid(stream, sid);
64+
kfree(SCTP_SO(stream, sid)->ext);
65+
SCTP_SO(stream, sid)->ext = NULL;
66+
}
67+
5568
/* Migrates chunks from stream queues to new stream queues if needed,
5669
* but not across associations. Also, removes those chunks to streams
5770
* higher than the new max.
@@ -70,16 +83,14 @@ static void sctp_stream_outq_migrate(struct sctp_stream *stream,
7083
* sctp_stream_update will swap ->out pointers.
7184
*/
7285
for (i = 0; i < outcnt; i++) {
73-
kfree(SCTP_SO(new, i)->ext);
86+
sctp_stream_free_ext(new, i);
7487
SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
7588
SCTP_SO(stream, i)->ext = NULL;
7689
}
7790
}
7891

79-
for (i = outcnt; i < stream->outcnt; i++) {
80-
kfree(SCTP_SO(stream, i)->ext);
81-
SCTP_SO(stream, i)->ext = NULL;
82-
}
92+
for (i = outcnt; i < stream->outcnt; i++)
93+
sctp_stream_free_ext(stream, i);
8394
}
8495

8596
static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
@@ -174,9 +185,9 @@ void sctp_stream_free(struct sctp_stream *stream)
174185
struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
175186
int i;
176187

177-
sched->free(stream);
188+
sched->unsched_all(stream);
178189
for (i = 0; i < stream->outcnt; i++)
179-
kfree(SCTP_SO(stream, i)->ext);
190+
sctp_stream_free_ext(stream, i);
180191
genradix_free(&stream->out);
181192
genradix_free(&stream->in);
182193
}

net/sctp/stream_sched.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ static int sctp_sched_fcfs_init_sid(struct sctp_stream *stream, __u16 sid,
4646
return 0;
4747
}
4848

49+
static void sctp_sched_fcfs_free_sid(struct sctp_stream *stream, __u16 sid)
50+
{
51+
}
52+
4953
static void sctp_sched_fcfs_free(struct sctp_stream *stream)
5054
{
5155
}
@@ -96,6 +100,7 @@ static struct sctp_sched_ops sctp_sched_fcfs = {
96100
.get = sctp_sched_fcfs_get,
97101
.init = sctp_sched_fcfs_init,
98102
.init_sid = sctp_sched_fcfs_init_sid,
103+
.free_sid = sctp_sched_fcfs_free_sid,
99104
.free = sctp_sched_fcfs_free,
100105
.enqueue = sctp_sched_fcfs_enqueue,
101106
.dequeue = sctp_sched_fcfs_dequeue,

net/sctp/stream_sched_prio.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,24 @@ static int sctp_sched_prio_init_sid(struct sctp_stream *stream, __u16 sid,
204204
return sctp_sched_prio_set(stream, sid, 0, gfp);
205205
}
206206

207+
static void sctp_sched_prio_free_sid(struct sctp_stream *stream, __u16 sid)
208+
{
209+
struct sctp_stream_priorities *prio = SCTP_SO(stream, sid)->ext->prio_head;
210+
int i;
211+
212+
if (!prio)
213+
return;
214+
215+
SCTP_SO(stream, sid)->ext->prio_head = NULL;
216+
for (i = 0; i < stream->outcnt; i++) {
217+
if (SCTP_SO(stream, i)->ext &&
218+
SCTP_SO(stream, i)->ext->prio_head == prio)
219+
return;
220+
}
221+
222+
kfree(prio);
223+
}
224+
207225
static void sctp_sched_prio_free(struct sctp_stream *stream)
208226
{
209227
struct sctp_stream_priorities *prio, *n;
@@ -323,6 +341,7 @@ static struct sctp_sched_ops sctp_sched_prio = {
323341
.get = sctp_sched_prio_get,
324342
.init = sctp_sched_prio_init,
325343
.init_sid = sctp_sched_prio_init_sid,
344+
.free_sid = sctp_sched_prio_free_sid,
326345
.free = sctp_sched_prio_free,
327346
.enqueue = sctp_sched_prio_enqueue,
328347
.dequeue = sctp_sched_prio_dequeue,

net/sctp/stream_sched_rr.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ static int sctp_sched_rr_init_sid(struct sctp_stream *stream, __u16 sid,
9090
return 0;
9191
}
9292

93+
static void sctp_sched_rr_free_sid(struct sctp_stream *stream, __u16 sid)
94+
{
95+
}
96+
9397
static void sctp_sched_rr_free(struct sctp_stream *stream)
9498
{
9599
sctp_sched_rr_unsched_all(stream);
@@ -177,6 +181,7 @@ static struct sctp_sched_ops sctp_sched_rr = {
177181
.get = sctp_sched_rr_get,
178182
.init = sctp_sched_rr_init,
179183
.init_sid = sctp_sched_rr_init_sid,
184+
.free_sid = sctp_sched_rr_free_sid,
180185
.free = sctp_sched_rr_free,
181186
.enqueue = sctp_sched_rr_enqueue,
182187
.dequeue = sctp_sched_rr_dequeue,

0 commit comments

Comments
 (0)