Код: Выделить всё
expr "`perl -e "print 'A' x1024"` * 0"
а в логах тем временем.....
Код: Выделить всё
pid 6059 (csh), uid 0: exited on signal 11
pid 5812 (csh), uid 1001: exited on signal 11
Модератор: vadim64
Код: Выделить всё
expr "`perl -e "print 'A' x1024"` * 0"
Код: Выделить всё
pid 6059 (csh), uid 0: exited on signal 11
pid 5812 (csh), uid 1001: exited on signal 11
Код: Выделить всё
unmatched `.
Код: Выделить всё
"`perl -e "print 'A' x1024"` * 0"
Код: Выделить всё
%csh `.
Unmatched `.
Код: Выделить всё
%su
Password:
%"`perl -e "print 'A' x1024"` * 0" > /root/FUCK
Unmatched `.
%whoami
beastie
%su
Password:
%cat ~/FUCK
%
%tail -n 1 /var/run/dmesg.boot
pid 72087 (csh), uid 0: exited on signal 11
Код: Выделить всё
===============/usr/src/contrib/tcsh/sh.glob.c=================
/*
* Command substitute cp. If literal, then this is a substitution from a
* << redirection, and so we should not crunch blanks and tabs, separating
* words only at newlines.
*/
Char **
dobackp(Char *cp, int literal)
{
struct Strbuf word = Strbuf_INIT;
struct blk_buf bb = BLK_BUF_INIT;
Char *lp, *rp, *ep;
cleanup_push(&bb, bb_cleanup);
cleanup_push(&word, Strbuf_cleanup);
for (;;) {
for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
;
Strbuf_appendn(&word, cp, lp - cp);
if (*lp == 0)
break;
lp++;
for (rp = lp; *rp && *rp != '`'; rp++)
if (*rp == '\\') {
rp++;
if (!*rp)
goto oops;
}
if (!*rp) {
oops:
stderror(ERR_UNMATCHED, '`'); #Вот по-этому оно проявляется
}
ep = Strnsave(lp, rp - lp);
cleanup_push(ep, xfree);
backeval(&bb, &word, ep, literal);
cleanup_until(ep);
cp = rp + 1;
}
if (word.len != 0)
pword(&bb, &word);
cleanup_ignore(&bb);
cleanup_until(&bb);
return bb_finish(&bb);
}
=======================/usr/src/contrib/tcsh/sh.lex.c======================================
/*
* PWP: this is dumb, but how all of the other shells work. If \ quotes
* a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY
* following character INSIDE a set of ''s.
*
* Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar
*/
if (c == (eChar)HIST)
c |= QUOTE;
else {
if (bslash_quote &&
((c == '\'') || (c == '"') ||
(c == '\\'))) {
c |= QUOTE;
}
else {
if (c == '\n')
/*
* if (c1 == '`') c = ' '; else #Похоже, это из-за того, что тут тупо просто закомменчено =))))
*/
c |= QUOTE;
ungetC(c);
c = '\\';
}
}
}
Код: Выделить всё
[root@zingel /sploit]# gdb /bin/csh
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...(no debugging symbols
found)...
(gdb) break main
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (main) pending.
(gdb) r
Starting program: /bin/csh
(no debugging symbols found)...(no debugging symbols found)...(no debugging
symbols found)...(no debugging symbols found)...(no debugging symbols
found)...%
(gdb) break main
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (main) pending.
(gdb) disass
Dump of assembler code for function read:
0x281f83cc <read+0>: mov $0x3,%eax
0x281f83d1 <read+5>: int $0x80
0x281f83d3 <read+7>: jb 0x281f83b8 <write+12>
0x281f83d5 <read+9>: ret
0x281f83d6 <read+10>: nop
0x281f83d7 <read+11>: nop
0x281f83d8 <read+12>: nop
0x281f83d9 <read+13>: nop
0x281f83da <read+14>: nop
0x281f83db <read+15>: nop
0x281f83dc <read+16>: nop
0x281f83dd <read+17>: nop
0x281f83de <read+18>: nop
0x281f83df <read+19>: nop
0x281f83e0 <read+20>: push %ebp
0x281f83e1 <read+21>: mov %esp,%ebp
0x281f83e3 <read+23>: push %ebx
0x281f83e4 <read+24>: call 0x2813f6f7 <_fini+200803> #От этого
0x281f83e9 <read+29>: add $0x1040f,%ebx
0x281f83ef <read+35>: sub $0x34,%esp
0x281f83f2 <read+38>: mov 0x147a4(%ebx),%eax
0x281f83f8 <read+44>: test %eax,%eax
---Type <return> to continue, or q <return> to quit---
0x281f83fa <read+46>: je 0x281f8402 <read+54>
0x281f83fc <read+48>: add $0x34,%esp
0x281f83ff <read+51>: pop %ebx
0x281f8400 <read+52>: pop %ebp
0x281f8401 <read+53>: ret #И до этого
---Type <return> to continue, or q <return> to quit---
(gdb) break *0x281f8401
Breakpoint 3 at 0x281f8401
(gdb) cont
Continuing.
%"`perl -e "print 'A' x1024"` * 0"
Unmatched `.
Program received signal SIGSEGV, Segmentation fault.
0x28183862 in calloc () from /lib/libc.so.7
(gdb) i r
eax 0x8092ef4 134819572
ecx 0xc 12
edx 0x8092ef4 134819572
ebx 0x282087f8 673220600
esp 0xbfbfe7b0 0xbfbfe7b0
ebp 0xbfbfe7f8 0xbfbfe7f8
esi 0x8000000 134217728
edi 0x1 1
eip 0x28183862 0x28183862
eflags 0x10297 66199
cs 0x33 51
ss 0x3b 59
ds 0x3b 59
es 0x3b 59
fs 0x3b 59
gs 0x1b 27
(gdb) x/5xw 0xbfbfe7f8
0xbfbfe7f8: 0xbfbfe828 0x28183b7e 0x283071f0 0x28307178
0xbfbfe808: 0x2818383b
(gdb) quit
The program is running. Exit anyway? (y or n) y
[root@zingel /sploit]#
http://www.freebsd.org/cgi/query-pr.cgi?pr=125185&cat=I tracked this down. Here is the explanation as I understand it.
The traceback from the segfault is as follows, for the record:
#0 0x000000080096cd1e in malloc () from /lib/libc.so.7
#1 0x000000080096cfee in free () from /lib/libc.so.7
#2 0x0000000000448066 in sfree (p=0x427e46)
at /usr/src/bin/csh/../../contrib/tcsh/tc.alloc.c:562
#3 0x0000000000450e79 in bb_cleanup (xbb=0x7fffffffdf70)
at /usr/src/bin/csh/../../contrib/tcsh/tc.str.c:521
#4 0x000000000040d450 in cleanup_until (last_var=0x57b730)
at /usr/src/bin/csh/../../contrib/tcsh/sh.err.c:444
#5 0x0000000000406423 in process (catch=1)
at /usr/src/bin/csh/../../contrib/tcsh/sh.c:2027
#6 0x0000000000404f5f in main (argc=0, argv=0x7fffffffe7d8)
at /usr/src/bin/csh/../../contrib/tcsh/sh.c:1304
However, the source of the bug is actually in the function `dobackp', sh.glob.c:646. tcsh has a "cleanup stack", where a function can push things to be cleaned up, and run them later. `dobackp' pushes some things on the cleanup stack, then detects the parse error and exits by calling stderror(). The problem is that the whole thing was being run in a subshell started with vfork(), so the stuff appears on the parent's cleanup stack, although they have pointers to objects that only existed for the child. (More specifically, pointers to a piece of the (regular) stack that is below the parent's current stack pointer, so it can get overwritten.) When the parent eventually runs its cleanup stack bad things happen.
If you run csh with the -F option, to use fork() instead of vfork(), it does not crash.
It would be easy to fix this specific instance of the bug, by calling cleanup_until() in `dobackp' before calling stderror(). Unfortunately, it looks like there are lots of places where the code tries to exit without cleaning up first, and it is not clear when they might be run in a vforked subshell. Here are some possibilities:
1. Audit the whole source to find and fix all places where a function may exit without popping the cleanup stack.
2. Set a mark on the stack as soon as vfork() returns in the child, and add code to xexit() or something to have it pop to that mark before exiting. I have not thought this through completely and am not sure if it is safe.
3. Stop using vfork() altogether. tcsh should really not be using it when there is non-trivial work for the child to do. How significant is the extra overhead of fork() in this day and age, when we have copy-on-write?
The upstream tcsh people might also have some ideas, but a bit of Googling did not reveal who they are.
--
Nate Eldredge
neldredge@math.ucsd.edu
(кстати проверьте)если юзать с опцией -F
оно не падает
хотя все там накрученоа эта опция токо меняет другой fork
а заначит проблема где то в стеке и его очистке после fork
Nate Eldredge
<neldredge@math.ucsd.edu> 4 декабря 2008 г. 3:41
Кому: bug-followup@freebsd.org, 666.root@gmail.com
Ответить | Ответить всем | Переслать | Печать | Удалить | Показать исходное сообщение
This is incorporated into bin/129405.
--
Nate Eldredge
neldredge@math.ucsd.edu
Код: Выделить всё
diff -ur tcsh.orig/sh.c src/contrib/tcsh/sh.c
--- tcsh.orig/sh.c 2007-10-16 09:18:39.000000000 -0700
+++ src/contrib/tcsh/sh.c 2008-12-03 16:11:53.000000000 -0800
@@ -89,8 +89,8 @@
int do_logout = 0;
#endif /* TESLA */
-
-int use_fork = 0; /* use fork() instead of vfork()? */
+/* Using vfork() has several bugs, so use fork() instead */
+int use_fork = 1; /* use fork() instead of vfork()? */
/*
* Magic pointer values. Used to specify other invalid conditions aside
@@ -908,9 +908,8 @@
case 'F':
/*
* This will cause children to be created using fork instead of
- * vfork.
+ * vfork. That is now the default, so this has no effect.
*/
- use_fork = 1;
break;
case ' ':
diff -ur tcsh.orig/tcsh.man src/contrib/tcsh/tcsh.man
--- tcsh.orig/tcsh.man 2008-07-10 10:07:27.000000000 -0700
+++ src/contrib/tcsh/tcsh.man 2008-12-03 16:11:36.000000000 -0800
@@ -133,7 +133,8 @@
command hashing, and thus starts faster.
.TP 4
.B \-F
-The shell uses \fIfork\fR(2) instead of \fIvfork\fR(2) to spawn processes. (+)
+The shell uses \fIfork\fR(2) instead of \fIvfork\fR(2) to spawn processes.
+This is now the default on FreeBSD so this option has no effect. (+)
.TP 4
.B \-i
The shell is interactive and prompts for its top-level input, even if