Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1308235 > unrolled thread
| Started by | Dmitry Vyukov <dvyukov@google.com> |
|---|---|
| First post | 2016-01-13 11:00 +0100 |
| Last post | 2016-01-21 18:40 +0100 |
| Articles | 7 — 4 participants |
Back to article view | Back to linux.kernel
net/sctp: use-after-free in __sctp_connect Dmitry Vyukov <dvyukov@google.com> - 2016-01-13 11:00 +0100
Re: net/sctp: use-after-free in __sctp_connect Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> - 2016-01-14 02:50 +0100
RE: net/sctp: use-after-free in __sctp_connect YUAN Jia <Jia.Yuan@alcatel-sbell.com.cn> - 2016-01-14 03:00 +0100
Re: net/sctp: use-after-free in __sctp_connect Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> - 2016-01-15 20:10 +0100
Re: net/sctp: use-after-free in __sctp_connect Vlad Yasevich <vyasevich@gmail.com> - 2016-01-19 15:40 +0100
Re: net/sctp: use-after-free in __sctp_connect Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> - 2016-01-21 18:20 +0100
Re: net/sctp: use-after-free in __sctp_connect Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> - 2016-01-21 18:40 +0100
| From | Dmitry Vyukov <dvyukov@google.com> |
|---|---|
| Date | 2016-01-13 11:00 +0100 |
| Subject | net/sctp: use-after-free in __sctp_connect |
| Message-ID | <qQqnD-6iI-3@gated-at.bofh.it> |
Hello,
The following program causes use-after-free in __sctp_connect:
// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
long r[13];
void *thr(void *arg)
{
switch ((long)arg) {
case 0:
r[0] = syscall(SYS_mmap, 0x20000000ul, 0x20000ul,
0x3ul, 0x32ul, 0xfffffffffffffffful, 0x0ul);
break;
case 1:
r[1] = syscall(SYS_socket, 0xaul, 0x1ul, 0x84ul, 0, 0, 0);
break;
case 2:
memcpy((void*)0x2000b000,
"\x0a\x00\x33\xe0\x49\xd0\x2e\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x4c\x37\xff\xc4",
28);
r[3] = syscall(SYS_bind, r[1], 0x2000b000ul, 0x1cul, 0, 0, 0);
break;
case 3:
r[4] = syscall(SYS_dup2, r[1], r[1], 0, 0, 0, 0);
break;
case 4:
*(uint64_t*)0x200177ed = (uint64_t)0x0;
*(uint64_t*)0x200177f5 = (uint64_t)0x2710;
r[7] = syscall(SYS_setsockopt, r[4], 0x1ul, 0x15ul,
0x200177edul, 0x10ul, 0);
break;
case 5:
*(uint16_t*)0x2000b008 = (uint16_t)0x2;
*(uint16_t*)0x2000b00a = (uint16_t)0xbab;
*(uint32_t*)0x2000b00c = (uint32_t)0xffffffff;
r[11] = syscall(SYS_setsockopt, r[4], 0x84ul, 0x6eul,
0x2000b000ul, 0x1cul, 0);
break;
case 6:
r[12] = syscall(SYS_shutdown, r[4], 0x1ul, 0, 0, 0, 0);
break;
}
return 0;
}
int main()
{
long i;
pthread_t th[7];
memset(r, -1, sizeof(r));
for (i = 0; i < 7; i++) {
pthread_create(&th[i], 0, thr, (void*)i);
usleep(10000);
}
for (i = 0; i < 7; i++) {
pthread_create(&th[i], 0, thr, (void*)i);
if (i%2==0)
usleep(10000);
}
usleep(100000);
return 0;
}
==================================================================
BUG: KASAN: use-after-free in __sctp_connect+0xb23/0xb90 at addr
ffff8800605febb8
Read of size 4 by task syz-executor/15263
INFO: Allocated in sctp_association_new+0x6f/0x1da0 age=0 cpu=3 pid=15267
[< none >] ___slab_alloc+0x486/0x4e0 mm/slub.c:2468
[< none >] __slab_alloc+0x66/0xc0 mm/slub.c:2497
[< inline >] slab_alloc_node mm/slub.c:2560
[< inline >] slab_alloc mm/slub.c:2602
[< none >] kmem_cache_alloc_trace+0x284/0x310 mm/slub.c:2619
[< inline >] kmalloc include/linux/slab.h:458
[< inline >] kzalloc include/linux/slab.h:602
[< none >] sctp_association_new+0x6f/0x1da0 net/sctp/associola.c:302
[< none >] __sctp_connect+0x4ec/0xb90 net/sctp/socket.c:1161
[< none >] __sctp_setsockopt_connectx+0x198/0x1d0
net/sctp/socket.c:1328
[< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
[< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
[< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
[< inline >] SYSC_setsockopt net/socket.c:1752
[< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
INFO: Freed in sctp_association_put+0x150/0x250 age=0 cpu=3 pid=15267
[< none >] __slab_free+0x1fc/0x320 mm/slub.c:2678
[< inline >] slab_free mm/slub.c:2833
[< none >] kfree+0x2a8/0x2d0 mm/slub.c:3662
[< inline >] sctp_association_destroy net/sctp/associola.c:424
[< none >] sctp_association_put+0x150/0x250 net/sctp/associola.c:860
[< none >] sctp_wait_for_connect+0x37c/0x4f0 net/sctp/socket.c:7067
[< none >] __sctp_connect+0x905/0xb90 net/sctp/socket.c:1215
[< none >] __sctp_setsockopt_connectx+0x198/0x1d0
net/sctp/socket.c:1328
[< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
[< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
[< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
[< inline >] SYSC_setsockopt net/socket.c:1752
[< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
INFO: Slab 0xffffea0001817e00 objects=7 used=3 fp=0xffff8800605fa3b0
flags=0x5fffc0000004080
INFO: Object 0xffff8800605feb10 @offset=27408 fp=0x (null)
CPU: 2 PID: 15263 Comm: syz-executor Tainted: G B 4.4.0+ #237
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
00000000ffffffff ffff88003717f8f0 ffffffff8290ea2d ffff88003e806a00
ffff8800605feb10 ffff8800605f8000 ffff88003717f920 ffffffff81730904
ffff88003e806a00 ffffea0001817e00 ffff8800605feb10 dffffc0000000000
Call Trace:
[<ffffffff81739e1e>] __asan_report_load4_noabort+0x3e/0x40
mm/kasan/report.c:294
[<ffffffff85925803>] __sctp_connect+0xb23/0xb90 net/sctp/socket.c:1217
[<ffffffff85925a08>] __sctp_setsockopt_connectx+0x198/0x1d0
net/sctp/socket.c:1328
[< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
[<ffffffff8592bf36>] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
[<ffffffff84d593a5>] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
[< inline >] SYSC_setsockopt net/socket.c:1752
[<ffffffff84d56548>] SyS_setsockopt+0x158/0x240 net/socket.c:1731
[<ffffffff85e8eb76>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
==================================================================
On commit 03891f9c853d5c4473224478a1e03ea00d70ff8d (Jan 11).
[toc] | [next] | [standalone]
| From | Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> |
|---|---|
| Date | 2016-01-14 02:50 +0100 |
| Message-ID | <qQFcZ-8cO-7@gated-at.bofh.it> |
| In reply to | #1308235 |
Em 13-01-2016 23:37, YUAN Jia escreveu: > Hi Dmitry, > > I've tested your program, but found nothing happens. So, I suspect it may cause kernel crash only on some special kernel version? > I was just using kernel of 4.2.3. What about you? > > Richard Please don't top-post. Note that it doesn't necessarily crashes the system. syzkaller is using kasan to detect such type of invalid accesses, which in some conditions may lead to crashes, weird behavior or just nothing at all. It all depends on how much the memory was already changed after it was freed. > -----Original Message----- > From: linux-sctp-owner@vger.kernel.org [mailto:linux-sctp-owner@vger.kernel.org] On Behalf Of Dmitry Vyukov > Sent: 2016年1月13日 17:53 > To: Vlad Yasevich; Neil Horman; David S. Miller; linux-sctp@vger.kernel.org; netdev; LKML; Eric Dumazet; Marcelo Ricardo Leitner > Cc: syzkaller; Kostya Serebryany; Alexander Potapenko; Sasha Levin > Subject: net/sctp: use-after-free in __sctp_connect > ... > > On commit 03891f9c853d5c4473224478a1e03ea00d70ff8d (Jan 11). This is the git commit/(version) he was using --^ Marcelo
[toc] | [prev] | [next] | [standalone]
| From | YUAN Jia <Jia.Yuan@alcatel-sbell.com.cn> |
|---|---|
| Date | 2016-01-14 03:00 +0100 |
| Message-ID | <qQFcZ-8cO-9@gated-at.bofh.it> |
| In reply to | #1308235 |
Hi Dmitry,
I've tested your program, but found nothing happens. So, I suspect it may cause kernel crash only on some special kernel version?
I was just using kernel of 4.2.3. What about you?
Richard
-----Original Message-----
From: linux-sctp-owner@vger.kernel.org [mailto:linux-sctp-owner@vger.kernel.org] On Behalf Of Dmitry Vyukov
Sent: 2016年1月13日 17:53
To: Vlad Yasevich; Neil Horman; David S. Miller; linux-sctp@vger.kernel.org; netdev; LKML; Eric Dumazet; Marcelo Ricardo Leitner
Cc: syzkaller; Kostya Serebryany; Alexander Potapenko; Sasha Levin
Subject: net/sctp: use-after-free in __sctp_connect
Hello,
The following program causes use-after-free in __sctp_connect:
// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
long r[13];
void *thr(void *arg)
{
switch ((long)arg) {
case 0:
r[0] = syscall(SYS_mmap, 0x20000000ul, 0x20000ul, 0x3ul, 0x32ul, 0xfffffffffffffffful, 0x0ul);
break;
case 1:
r[1] = syscall(SYS_socket, 0xaul, 0x1ul, 0x84ul, 0, 0, 0);
break;
case 2:
memcpy((void*)0x2000b000, "\x0a\x00\x33\xe0\x49\xd0\x2e\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x4c\x37\xff\xc4",
28);
r[3] = syscall(SYS_bind, r[1], 0x2000b000ul, 0x1cul, 0, 0, 0);
break;
case 3:
r[4] = syscall(SYS_dup2, r[1], r[1], 0, 0, 0, 0);
break;
case 4:
*(uint64_t*)0x200177ed = (uint64_t)0x0;
*(uint64_t*)0x200177f5 = (uint64_t)0x2710;
r[7] = syscall(SYS_setsockopt, r[4], 0x1ul, 0x15ul, 0x200177edul, 0x10ul, 0);
break;
case 5:
*(uint16_t*)0x2000b008 = (uint16_t)0x2;
*(uint16_t*)0x2000b00a = (uint16_t)0xbab;
*(uint32_t*)0x2000b00c = (uint32_t)0xffffffff;
r[11] = syscall(SYS_setsockopt, r[4], 0x84ul, 0x6eul, 0x2000b000ul, 0x1cul, 0);
break;
case 6:
r[12] = syscall(SYS_shutdown, r[4], 0x1ul, 0, 0, 0, 0);
break;
}
return 0;
}
int main()
{
long i;
pthread_t th[7];
memset(r, -1, sizeof(r));
for (i = 0; i < 7; i++) {
pthread_create(&th[i], 0, thr, (void*)i);
usleep(10000);
}
for (i = 0; i < 7; i++) {
pthread_create(&th[i], 0, thr, (void*)i);
if (i%2==0)
usleep(10000);
}
usleep(100000);
return 0;
}
==================================================================
BUG: KASAN: use-after-free in __sctp_connect+0xb23/0xb90 at addr
ffff8800605febb8
Read of size 4 by task syz-executor/15263
INFO: Allocated in sctp_association_new+0x6f/0x1da0 age=0 cpu=3 pid=15267
[< none >] ___slab_alloc+0x486/0x4e0 mm/slub.c:2468
[< none >] __slab_alloc+0x66/0xc0 mm/slub.c:2497
[< inline >] slab_alloc_node mm/slub.c:2560
[< inline >] slab_alloc mm/slub.c:2602
[< none >] kmem_cache_alloc_trace+0x284/0x310 mm/slub.c:2619
[< inline >] kmalloc include/linux/slab.h:458
[< inline >] kzalloc include/linux/slab.h:602
[< none >] sctp_association_new+0x6f/0x1da0 net/sctp/associola.c:302
[< none >] __sctp_connect+0x4ec/0xb90 net/sctp/socket.c:1161
[< none >] __sctp_setsockopt_connectx+0x198/0x1d0
net/sctp/socket.c:1328
[< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
[< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
[< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
[< inline >] SYSC_setsockopt net/socket.c:1752
[< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
INFO: Freed in sctp_association_put+0x150/0x250 age=0 cpu=3 pid=15267
[< none >] __slab_free+0x1fc/0x320 mm/slub.c:2678
[< inline >] slab_free mm/slub.c:2833
[< none >] kfree+0x2a8/0x2d0 mm/slub.c:3662
[< inline >] sctp_association_destroy net/sctp/associola.c:424
[< none >] sctp_association_put+0x150/0x250 net/sctp/associola.c:860
[< none >] sctp_wait_for_connect+0x37c/0x4f0 net/sctp/socket.c:7067
[< none >] __sctp_connect+0x905/0xb90 net/sctp/socket.c:1215
[< none >] __sctp_setsockopt_connectx+0x198/0x1d0
net/sctp/socket.c:1328
[< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
[< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
[< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
[< inline >] SYSC_setsockopt net/socket.c:1752
[< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
INFO: Slab 0xffffea0001817e00 objects=7 used=3 fp=0xffff8800605fa3b0
flags=0x5fffc0000004080
INFO: Object 0xffff8800605feb10 @offset=27408 fp=0x (null)
CPU: 2 PID: 15263 Comm: syz-executor Tainted: G B 4.4.0+ #237
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 00000000ffffffff ffff88003717f8f0 ffffffff8290ea2d ffff88003e806a00
ffff8800605feb10 ffff8800605f8000 ffff88003717f920 ffffffff81730904
ffff88003e806a00 ffffea0001817e00 ffff8800605feb10 dffffc0000000000 Call Trace:
[<ffffffff81739e1e>] __asan_report_load4_noabort+0x3e/0x40
mm/kasan/report.c:294
[<ffffffff85925803>] __sctp_connect+0xb23/0xb90 net/sctp/socket.c:1217 [<ffffffff85925a08>] __sctp_setsockopt_connectx+0x198/0x1d0
net/sctp/socket.c:1328
[< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
[<ffffffff8592bf36>] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728 [<ffffffff84d593a5>] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
[< inline >] SYSC_setsockopt net/socket.c:1752
[<ffffffff84d56548>] SyS_setsockopt+0x158/0x240 net/socket.c:1731 [<ffffffff85e8eb76>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
==================================================================
On commit 03891f9c853d5c4473224478a1e03ea00d70ff8d (Jan 11).
--
To unsubscribe from this list: send the line "unsubscribe linux-sctp" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[toc] | [prev] | [next] | [standalone]
| From | Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> |
|---|---|
| Date | 2016-01-15 20:10 +0100 |
| Message-ID | <qRhUZ-1WI-1@gated-at.bofh.it> |
| In reply to | #1308235 |
On Wed, Jan 13, 2016 at 10:52:31AM +0100, Dmitry Vyukov wrote:
> Hello,
>
> The following program causes use-after-free in __sctp_connect:
>
...
> INFO: Freed in sctp_association_put+0x150/0x250 age=0 cpu=3 pid=15267
> [< none >] __slab_free+0x1fc/0x320 mm/slub.c:2678
> [< inline >] slab_free mm/slub.c:2833
> [< none >] kfree+0x2a8/0x2d0 mm/slub.c:3662
> [< inline >] sctp_association_destroy net/sctp/associola.c:424
> [< none >] sctp_association_put+0x150/0x250 net/sctp/associola.c:860
> [< none >] sctp_wait_for_connect+0x37c/0x4f0 net/sctp/socket.c:7067
^^^^^^^^^^^^^^
> [< none >] __sctp_connect+0x905/0xb90 net/sctp/socket.c:1215
> [< none >] __sctp_setsockopt_connectx+0x198/0x1d0
> net/sctp/socket.c:1328
> [< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
> [< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
> [< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
> [< inline >] SYSC_setsockopt net/socket.c:1752
> [< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
> [< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
> arch/x86/entry/entry_64.S:185
This one may sher some light on that other socket leak one, because the
association shouldn't have been freed at that point.
Now, how it managed to unbalance that refcnt, hmm...
[toc] | [prev] | [next] | [standalone]
| From | Vlad Yasevich <vyasevich@gmail.com> |
|---|---|
| Date | 2016-01-19 15:40 +0100 |
| Message-ID | <qSFBT-HG-1@gated-at.bofh.it> |
| In reply to | #1310375 |
On 01/15/2016 02:01 PM, Marcelo Ricardo Leitner wrote: > On Wed, Jan 13, 2016 at 10:52:31AM +0100, Dmitry Vyukov wrote: >> Hello, >> >> The following program causes use-after-free in __sctp_connect: >> > ... >> INFO: Freed in sctp_association_put+0x150/0x250 age=0 cpu=3 pid=15267 >> [< none >] __slab_free+0x1fc/0x320 mm/slub.c:2678 >> [< inline >] slab_free mm/slub.c:2833 >> [< none >] kfree+0x2a8/0x2d0 mm/slub.c:3662 >> [< inline >] sctp_association_destroy net/sctp/associola.c:424 >> [< none >] sctp_association_put+0x150/0x250 net/sctp/associola.c:860 >> [< none >] sctp_wait_for_connect+0x37c/0x4f0 net/sctp/socket.c:7067 > ^^^^^^^^^^^^^^ >> [< none >] __sctp_connect+0x905/0xb90 net/sctp/socket.c:1215 >> [< none >] __sctp_setsockopt_connectx+0x198/0x1d0 >> net/sctp/socket.c:1328 >> [< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360 >> [< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728 >> [< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642 >> [< inline >] SYSC_setsockopt net/socket.c:1752 >> [< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731 >> [< none >] entry_SYSCALL_64_fastpath+0x16/0x7a >> arch/x86/entry/entry_64.S:185 > > This one may sher some light on that other socket leak one, because the > association shouldn't have been freed at that point. > Now, how it managed to unbalance that refcnt, hmm... > The free may be a result of implicit close when the program ends. If the thread is still waiting for connect to finish when the program ends, we may end up in a situation when the association has been freed, but the ref held by wait_for_connect prevents the destruction. When wait_for_connect finishes in puts the ref and causes the destruction. What I am guessing is happing is the wait_for_connect doesn't catch the error condition correctly and thus __sctp_connect() doesn't think there was and error and references the assoc which was just destroyed. -vlad
[toc] | [prev] | [next] | [standalone]
| From | Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> |
|---|---|
| Date | 2016-01-21 18:20 +0100 |
| Message-ID | <qTr3Q-8oL-19@gated-at.bofh.it> |
| In reply to | #1312295 |
On Tue, Jan 19, 2016 at 09:38:54AM -0500, Vlad Yasevich wrote:
> On 01/15/2016 02:01 PM, Marcelo Ricardo Leitner wrote:
> > On Wed, Jan 13, 2016 at 10:52:31AM +0100, Dmitry Vyukov wrote:
> >> Hello,
> >>
> >> The following program causes use-after-free in __sctp_connect:
> >>
> > ...
> >> INFO: Freed in sctp_association_put+0x150/0x250 age=0 cpu=3 pid=15267
> >> [< none >] __slab_free+0x1fc/0x320 mm/slub.c:2678
> >> [< inline >] slab_free mm/slub.c:2833
> >> [< none >] kfree+0x2a8/0x2d0 mm/slub.c:3662
> >> [< inline >] sctp_association_destroy net/sctp/associola.c:424
> >> [< none >] sctp_association_put+0x150/0x250 net/sctp/associola.c:860
> >> [< none >] sctp_wait_for_connect+0x37c/0x4f0 net/sctp/socket.c:7067
> > ^^^^^^^^^^^^^^
> >> [< none >] __sctp_connect+0x905/0xb90 net/sctp/socket.c:1215
> >> [< none >] __sctp_setsockopt_connectx+0x198/0x1d0
> >> net/sctp/socket.c:1328
> >> [< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
> >> [< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
> >> [< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
> >> [< inline >] SYSC_setsockopt net/socket.c:1752
> >> [< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
> >> [< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
> >> arch/x86/entry/entry_64.S:185
> >
> > This one may sher some light on that other socket leak one, because the
> > association shouldn't have been freed at that point.
> > Now, how it managed to unbalance that refcnt, hmm...
> >
>
> The free may be a result of implicit close when the program ends. If the thread
> is still waiting for connect to finish when the program ends, we may end up
> in a situation when the association has been freed, but the ref held by wait_for_connect
> prevents the destruction. When wait_for_connect finishes in puts the ref and
> causes the destruction.
That could be it, yes.
> What I am guessing is happing is the wait_for_connect doesn't catch the error condition
> correctly and thus __sctp_connect() doesn't think there was and error and references
> the assoc which was just destroyed.
Perfect. There is another thing that this program exploits that, in this
case, leads to this. It's creating a tcp-style socket, calling connect()
on it in one thread and sendto() to a different peer in the main thread
probably while the connect is still in progress. Seems that can lead to
one having two assocs on a tcp-style socket, because we don't check if
we the socket has associations but if it's in established state. I don't
see the checks on sctp_sendmsg() protecting from this case.
2511 14:55:10 socket(PF_INET6, SOCK_STREAM, IPPROTO_SCTP) = 3
<0.000366>
2511 14:55:10 mmap(0x20000000, 65536, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x20000000 <0.000082>
2511 14:55:10 bind(3, {sa_family=AF_INET6, sin6_port=htons(13280),
inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=1882116169,
sin6_scope_id=3305060172}, 28) = 0 <0.000119>
- bound to IPv6
2511 14:55:10 mmap(NULL, 8392704, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f52f9e75000 <0.000084>
2511 14:55:10 brk(0) = 0x1cf8000 <0.000065>
2511 14:55:10 brk(0x1d19000) = 0x1d19000 <0.000079>
2511 14:55:10 brk(0) = 0x1d19000 <0.000064>
2511 14:55:10 mprotect(0x7f52f9e75000, 4096, PROT_NONE) = 0 <0.000091>
2511 14:55:10 clone(child_stack=0x7f52fa674ff0,
flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
parent_tidptr=0x7f52fa6759d0, tls=0x7f52fa675700,
child_tidptr=0x7f52fa6759d0) = 2512 <0.000211>
2511 14:55:10 setsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=6, linger=0},
8 <unfinished ...>
2512 14:55:10 set_robust_list(0x7f52fa6759e0, 24 <unfinished ...>
2511 14:55:10 <... setsockopt resumed> ) = 0 <0.000135>
2512 14:55:10 <... set_robust_list resumed> ) = 0 <0.000133>
2511 14:55:10 sendfile(3, 3, [0], 192 <unfinished ...>
2512 14:55:10 connect(3, {sa_family=AF_INET, sin_port=htons(13273),
sin_addr=inet_addr("127.0.0.1")}, 128 <unfinished ...>
- connect to IPv4. This connect should timeout, as we can't find a
route between ipv4/ipv6.
- no packet is sent due to this
2511 14:55:10 <... sendfile resumed> ) = -1 ESPIPE (Illegal seek)
<0.000146>
2511 14:55:10 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 <0.000066>
2511 14:55:10 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
<0.000065>
2511 14:55:10 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 <0.000067>
2511 14:55:10 nanosleep({4, 0}, 0x7ffffd73eee0) = 0 <4.000258>
- added a sleep(4) to make this more evident
2511 14:55:14 sendto(3,
"\0\0\0\0\0\0\0\1\335\1\370\375\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
112, 0, {sa_family=AF_INET6, sin6_port=htons(13276), inet_pton(AF_INET6,
"::1", &sin6_addr), sin6_flowinfo=3512421652, sin6_scope_id=4260889053},
128) = 112 <0.001601>
- sendto() to an IPv6 addr while connect() is still running.
- socket is not in established state.
- assoc is not a peeled off, as we can't find a transport using this
tuple
- so this new assoc ends up being allowed under a tcp-style socket
- nobody is listening on 13276. An ABORT is sent back
2512 14:55:14 <... connect resumed> ) = -1 ECONNREFUSED (Connection
refused) <4.003595>
- And suddenly the connect() is confused and thinks the error was for
it, exact after sendto() auto-association noticed the error.
- Funny thing is, as sendto() thinks it succeeded, as connect() already
consumed the error via sctp_error().
If the program was ending and if the threads awakening were the other
way around, e.g. if connect() had started a bit after sendto(),
connect() probably would have thought it succeeded, and referenced the
freed memory.
I'm thinking we should add a function to better identify busy sockets
such as this. Like in __sctp_connect(), issuing connect()s in parallel
will also fool current checks. Thoughts?
Marcelo
[toc] | [prev] | [next] | [standalone]
| From | Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> |
|---|---|
| Date | 2016-01-21 18:40 +0100 |
| Message-ID | <qTrnb-5X-15@gated-at.bofh.it> |
| In reply to | #1314362 |
On Thu, Jan 21, 2016 at 03:18:18PM -0200, Marcelo Ricardo Leitner wrote:
> On Tue, Jan 19, 2016 at 09:38:54AM -0500, Vlad Yasevich wrote:
> > On 01/15/2016 02:01 PM, Marcelo Ricardo Leitner wrote:
> > > On Wed, Jan 13, 2016 at 10:52:31AM +0100, Dmitry Vyukov wrote:
> > >> Hello,
> > >>
> > >> The following program causes use-after-free in __sctp_connect:
> > >>
> > > ...
> > >> INFO: Freed in sctp_association_put+0x150/0x250 age=0 cpu=3 pid=15267
> > >> [< none >] __slab_free+0x1fc/0x320 mm/slub.c:2678
> > >> [< inline >] slab_free mm/slub.c:2833
> > >> [< none >] kfree+0x2a8/0x2d0 mm/slub.c:3662
> > >> [< inline >] sctp_association_destroy net/sctp/associola.c:424
> > >> [< none >] sctp_association_put+0x150/0x250 net/sctp/associola.c:860
> > >> [< none >] sctp_wait_for_connect+0x37c/0x4f0 net/sctp/socket.c:7067
> > > ^^^^^^^^^^^^^^
> > >> [< none >] __sctp_connect+0x905/0xb90 net/sctp/socket.c:1215
> > >> [< none >] __sctp_setsockopt_connectx+0x198/0x1d0
> > >> net/sctp/socket.c:1328
> > >> [< inline >] sctp_setsockopt_connectx net/sctp/socket.c:1360
> > >> [< none >] sctp_setsockopt+0x226/0x3630 net/sctp/socket.c:3728
> > >> [< none >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2642
> > >> [< inline >] SYSC_setsockopt net/socket.c:1752
> > >> [< none >] SyS_setsockopt+0x158/0x240 net/socket.c:1731
> > >> [< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
> > >> arch/x86/entry/entry_64.S:185
> > >
> > > This one may sher some light on that other socket leak one, because the
> > > association shouldn't have been freed at that point.
> > > Now, how it managed to unbalance that refcnt, hmm...
> > >
> >
> > The free may be a result of implicit close when the program ends. If the thread
> > is still waiting for connect to finish when the program ends, we may end up
> > in a situation when the association has been freed, but the ref held by wait_for_connect
> > prevents the destruction. When wait_for_connect finishes in puts the ref and
> > causes the destruction.
>
> That could be it, yes.
>
> > What I am guessing is happing is the wait_for_connect doesn't catch the error condition
> > correctly and thus __sctp_connect() doesn't think there was and error and references
> > the assoc which was just destroyed.
>
> Perfect. There is another thing that this program exploits that, in this
> case, leads to this. It's creating a tcp-style socket, calling connect()
> on it in one thread and sendto() to a different peer in the main thread
> probably while the connect is still in progress. Seems that can lead to
> one having two assocs on a tcp-style socket, because we don't check if
> we the socket has associations but if it's in established state. I don't
> see the checks on sctp_sendmsg() protecting from this case.
>
> 2511 14:55:10 socket(PF_INET6, SOCK_STREAM, IPPROTO_SCTP) = 3
> <0.000366>
> 2511 14:55:10 mmap(0x20000000, 65536, PROT_READ|PROT_WRITE,
> MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x20000000 <0.000082>
> 2511 14:55:10 bind(3, {sa_family=AF_INET6, sin6_port=htons(13280),
> inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=1882116169,
> sin6_scope_id=3305060172}, 28) = 0 <0.000119>
> - bound to IPv6
>
> 2511 14:55:10 mmap(NULL, 8392704, PROT_READ|PROT_WRITE,
> MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f52f9e75000 <0.000084>
> 2511 14:55:10 brk(0) = 0x1cf8000 <0.000065>
> 2511 14:55:10 brk(0x1d19000) = 0x1d19000 <0.000079>
> 2511 14:55:10 brk(0) = 0x1d19000 <0.000064>
> 2511 14:55:10 mprotect(0x7f52f9e75000, 4096, PROT_NONE) = 0 <0.000091>
> 2511 14:55:10 clone(child_stack=0x7f52fa674ff0,
> flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
> parent_tidptr=0x7f52fa6759d0, tls=0x7f52fa675700,
> child_tidptr=0x7f52fa6759d0) = 2512 <0.000211>
> 2511 14:55:10 setsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=6, linger=0},
> 8 <unfinished ...>
> 2512 14:55:10 set_robust_list(0x7f52fa6759e0, 24 <unfinished ...>
> 2511 14:55:10 <... setsockopt resumed> ) = 0 <0.000135>
> 2512 14:55:10 <... set_robust_list resumed> ) = 0 <0.000133>
> 2511 14:55:10 sendfile(3, 3, [0], 192 <unfinished ...>
> 2512 14:55:10 connect(3, {sa_family=AF_INET, sin_port=htons(13273),
> sin_addr=inet_addr("127.0.0.1")}, 128 <unfinished ...>
> - connect to IPv4. This connect should timeout, as we can't find a
> route between ipv4/ipv6.
> - no packet is sent due to this
>
> 2511 14:55:10 <... sendfile resumed> ) = -1 ESPIPE (Illegal seek)
> <0.000146>
> 2511 14:55:10 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 <0.000066>
> 2511 14:55:10 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
> <0.000065>
> 2511 14:55:10 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 <0.000067>
> 2511 14:55:10 nanosleep({4, 0}, 0x7ffffd73eee0) = 0 <4.000258>
> - added a sleep(4) to make this more evident
>
> 2511 14:55:14 sendto(3,
> "\0\0\0\0\0\0\0\1\335\1\370\375\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
> 112, 0, {sa_family=AF_INET6, sin6_port=htons(13276), inet_pton(AF_INET6,
> "::1", &sin6_addr), sin6_flowinfo=3512421652, sin6_scope_id=4260889053},
> 128) = 112 <0.001601>
> - sendto() to an IPv6 addr while connect() is still running.
> - socket is not in established state.
> - assoc is not a peeled off, as we can't find a transport using this
> tuple
> - so this new assoc ends up being allowed under a tcp-style socket
> - nobody is listening on 13276. An ABORT is sent back
>
> 2512 14:55:14 <... connect resumed> ) = -1 ECONNREFUSED (Connection
> refused) <4.003595>
> - And suddenly the connect() is confused and thinks the error was for
> it, exact after sendto() auto-association noticed the error.
> - Funny thing is, as sendto() thinks it succeeded, as connect() already
> consumed the error via sctp_error().
>
> If the program was ending and if the threads awakening were the other
> way around, e.g. if connect() had started a bit after sendto(),
> connect() probably would have thought it succeeded, and referenced the
> freed memory.
Hmm connect() doesn't have to start after sendto(), no, as they are
waiting on different wq. Seems it has to wake the connect thread via
sctp_write_space() or sctp_wake_up_waiters(), via sctp_wfree(), which is
set as destructor upon sctp_sendmsg(). So when that chunk is freed, the
connect() returns, seems to make sense to me.
> I'm thinking we should add a function to better identify busy sockets
> such as this. Like in __sctp_connect(), issuing connect()s in parallel
> will also fool current checks. Thoughts?
>
> Marcelo
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web