Summary: | (toolchain) artsdsp stack smashing attack in function read() | ||
---|---|---|---|
Product: | Gentoo Linux | Reporter: | Ole Tange <bugs.gentoo.org> |
Component: | Hardened | Assignee: | The Gentoo Linux Hardened Team <hardened> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | gentoo-bugger, kevquinn |
Priority: | High | ||
Version: | unspecified | ||
Hardware: | All | ||
OS: | Linux | ||
Whiteboard: | audit | ||
Package list: | Runtime testing required: | --- | |
Bug Depends on: | 65892 | ||
Bug Blocks: | |||
Attachments: |
Output from emerge info
strace Simple testcase Full strace untested patch against ssp.c a working patch patch against glibc-2.3.4.20040808-r1 a more complete testcase |
Description
Ole Tange
2004-10-06 10:58:33 UTC
Created attachment 41237 [details]
Output from emerge info
I don't us qt/arts myself so I can't test this but a ssp in a read() should never happen. Please post the uncompressed output of strace -v -i -f artsdsp Created attachment 41509 [details]
strace
Created attachment 44433 [details]
Simple testcase
It took me a few days to track this bug down. It seems like the tsack smash
protector always hits in if you LD_PRELOAD a lib which overrides read(2) and at
some point hands the access down to the original read routine.
I stripped down the file artsdsp.c to the attached file. Compiled as an so and
try
strace -vif -E LD_PRELOAD="libtester.so.0.0.0:/lib/libdl.so.2" test
Whichever app you call that way, the very first read() command will die out
like this (full strace follows):
[400642ca] rt_sigaction(SIGRTMIN, {0x4015b170, [], 0}, NULL, 8) = 0
[400642ca] rt_sigaction(SIGRT_1, {0x4015b1b0, [], 0}, NULL, 8) = 0
[400642ca] rt_sigaction(SIGRT_2, {0x4015b280, [], 0}, NULL, 8) = 0
[4006450d] rt_sigprocmask(SIG_BLOCK, [RTMIN], NULL, 8) = 0
[4006450d] rt_sigprocmask(SIG_UNBLOCK, [RT_1], NULL, 8) = 0
[400f25a6] _sysctl({{CTL_KERN, KERN_VERSION}, 2, 0xbfffeaa4, 32, (nil), 0}) = 0
[400e3258] open("/dev/urandom", O_RDONLY) = 3
[400e3498] write(2, "read(3, 0x4014ec84, 4): in\n", 27read(3, 0x4014ec84, 4):
in
) = 27
[400e3498] write(2, "init(): in\n", 11init(): in
) = 11
[400eaeab] brk(0) = 0x804e000
[400eaeab] brk(0x806f000) = 0x806f000
[400e3498] write(2, "init(): out\n", 12init(): out
) = 12
[400e3418] read(3, "\260\367{_", 4) = 4
[400e3498] write(2, "read(): out\n", 12read(): out
) = 12
[4006450d] rt_sigprocmask(SIG_BLOCK, ~[ABRT], NULL, 8) = 0
[400e3498] write(2, "test: stack smashing attack in f"..., 44test: stack
smashing attack in function read) = 44
[400e3498] write(2, "()\n", 3()
) = 3
[400f3682] socket(PF_UNIX, SOCK_DGRAM, 0) = 4
[400f3596] sendto(4, "<2>test: stack smashing attack i"..., 47, 0,
{sa_family=AF_UNIX, path="/dev/log"}, 110) = 47
[400642ca] rt_sigaction(SIGABRT, {SIG_DFL}, NULL, 8) = 0
[400c22d7] getpid() = 21296
[40064591] kill(21296, SIGABRT) = 0
[40064591] --- SIGABRT (Aborted) @ 0 (0) ---
upeek: ptrace(PTRACE_PEEKUSER,21296,48,0): No such process
[????????] +++ killed by SIGABRT +++
I guess that reading from /dev/urandom is line 84 in
sysdeps/unix/sysv/linux/ssp.c in glibc-2.3.4.20040808-r1? So why does it die
there?
Created attachment 44434 [details]
Full strace
Maybe it helps if __libc_read() was used instead of read() in ssp.c? Haven't tried that though. Just had the same, with skype. artsdsp is a shell script which sets LD_PRELOAD to /usr/kde/3.3/lib/libartsdsp.so.0:/usr/kde/3.3/lib/libartsc.so.0:/lib/libdl.so.2 Quick experiments narrow it down to libartsdsp.so.0: $ LD_PRELOAD=/usr/kde/3.3/lib/libartsdsp.so.0 /bin/echo echo: stack smashing attack in function read() Aborted $ readelf -s /usr/kde/3.3/lib/libartsdsp.so.0 | grep read 20: 00000000 118 FUNC GLOBAL DEFAULT UND arts_read 29: 000019b0 248 FUNC GLOBAL DEFAULT 10 read so the culprit is a read() function defined in libartsdsp.so.0 (not the libc read() function). At this point we need someone conversant with KDE innards. artsc/artscbackend.cc contains a read() function, which presumably has the stack overflow. However it's not immediately obvious. Created attachment 49002 [details, diff]
untested patch against ssp.c
This is (AFAICS) not a KDE/aRts problem but a problem with the glibc smash
stack protector. That one uses read() to get the canary from /dev/urandom.
Unfortunately does artsdsp LD_PRELOAD its own read() routine which has his own
canary which doesn't get initialized correctly. So this affects all apps which
overload read(), probably also esound -- have a look at the testcase I attached
to have a sample independent from arts.
My guess is that it would help if the SSP initialization routine used
__libc_read() (which is not overloadable), like the attached patch does. I'd
try it if I knew how to install (and debug) a parrallel glibc install without
trashing my system :)
> I'd try it if I knew how to install (and debug) a
> parrallel glibc install without trashing my system :)
Consider taking a look at vserver. Vserver can run
mutiple linux-installations on the same hardware box.
(Kind of VMware but without the overhead).
When you trash one installation you simply do a cp -a.
Just tried the suggestion in #8, replacing read() with __libc_read() - it Works For Me, great stuff. Perhaps all the libc calls made in ssp.c (there are quite a few) should be coded to the internal names to avoid them being overloaded in this way - does that make sense? Kevin, yes it sure does make logical sense to convert all the functions over to libc internal ones. There was another bug open about that but the ball got dropped on it. Created attachment 49140 [details, diff]
a working patch
This is a tested patch against ssp.c. I replaced all calls which have internal
protected equivalences with those. It works but its possible that I made some
errors as I could not find any documentation at all on those glibc macros and
internals.
Please review.
Created attachment 49141 [details, diff]
patch against glibc-2.3.4.20040808-r1
Created attachment 49142 [details]
a more complete testcase
Try 'gmake -f tester.mk' -- if the bug is still there, the SSP will hit in
libtester_::read(), else in tester_::main():
(0) otherland /mnt/dummy/tmp/ssptest # gmake -f tester.mk test
make: Circular Makefile.c <- Makefile dependency dropped.
rm -f libtester_.so libtester_.c
rm -f tester_ tester_.c
sed -ne '/^libtester_.c.in/,/^[^\t]/{s/^\(\t\|[^\t].*\)//;p}' Makefile >
libtester_.c
cc -fstack-protector -rdynamic libtester_.c -o libtester_.so -shared
sed -ne '/^tester_.c.in/,/^[^\t]/{s/^\(\t\|[^\t].*\)//;p}' Makefile > tester_.c
cc -fstack-protector tester_.c -o tester_
LD_PRELOAD="./libtester_.so:/lib/libdl.so.2" ./tester_
libtester_.c:22
libtester_.c:14
libtester_.c:17
libtester_.c:25
tester_: stack smashing attack in function read()
make: *** [test] Aborted
(2) otherland /mnt/dummy/tmp/ssptest # chroot /mnt/dummy/
otherland / # cd tmp/ssptest/
otherland /tmp/ssptest # gmake -f tester.mk test
make: Circular Makefile.c <- Makefile dependency dropped.
LD_PRELOAD="./libtester_.so:/lib/libdl.so.2" ./tester_
tester_.c:6
tester_.c:8
tester_: stack smashing attack in function main()
make: *** [test] Aborted
Been running the most recent patch from #13 here for a couple of days without any trouble. Test case from #14 gives the same results as described in #14. artsdsp no longer fails. Just seen bug #65892, which seems to be heading for a fix that'll achieve the same result. I'd suggest the fix in that bug could make this bug obsolete. This has been fixed for a while, now. |