[Attaching after process 2761 fork to child process 2776]
[New inferior 2 (process 2776)]
[Detaching after fork from parent process 2761]
[Inferior 1 (process 2761) detached]
Thread 2.1 "uftpd" received signal SIGSEGV, Segmentation fault.
[Switching to process 2776]
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:65
65 ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
(gdb) x/i $Pc
Value can't be converted to integer.
(gdb) x/i $pc
=> 0x7f3898d354e5 <__strlen_avx2+21>: vpcmpeqb (%rdi),%ymm0,%ymm1
(gdb) disass
Dump of assembler code for function __strlen_avx2:
0x00007f3898d354d0 <+0>: endbr64
0x00007f3898d354d4 <+4>: mov %edi,%ecx
0x00007f3898d354d6 <+6>: mov %rdi,%rdx
0x00007f3898d354d9 <+9>: vpxor %xmm0,%xmm0,%xmm0
0x00007f3898d354dd <+13>: and $0x3f,%ecx
0x00007f3898d354e0 <+16>: cmp $0x20,%ecx
0x00007f3898d354e3 <+19>: ja 0x7f3898d35510 <__strlen_avx2+64>
=> 0x00007f3898d354e5 <+21>: vpcmpeqb (%rdi),%ymm0,%ymm1
(gdb) where
#0 __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:65
#1 0x0000556208652768 in handle_CWD (ctrl=0x556208bd0550, path=<optimized out>) at ftpcmd.c:407
#2 0x0000556208654c37 in read_client_command (w=<optimized out>, arg=0x556208bd0550, events=<optimized out>) at ftpcmd.c:1586
#3 0x00007f3898daad37 in uev_run (ctx=0x556208bd0520, flags=flags@entry=0) at uev.c:415
#4 0x0000556208656a96 in ftp_command (ctrl=0x556208bd0550) at ftpcmd.c:1610
#5 ftp_session (ctx=<optimized out>, sd=<optimized out>) at ftpcmd.c:1652
#6 0x00007f3898daad37 in uev_run (ctx=0x7ffcf35ccf60, flags=0) at uev.c:415
#7 0x0000556208650597 in serve_files (ctx=0x7ffcf35ccf60) at uftpd.c:247
#8 main (argc=<optimized out>, argv=<optimized out>) at uftpd.c:405
the relevant source code in ftpcmd.c
static void handle_CWD(ctrl_t *ctrl, char *path)
{
struct stat st;
char *dir;
if (!path)
goto done;
/*
* Some FTP clients, most notably Chrome, use CWD to check if an
* entry is a file or directory.
*/
dir = compose_abspath(ctrl, path);
if (!dir || stat(dir, &st) || !S_ISDIR(st.st_mode)) {
DBG("chrooted:%d, ctrl->cwd: %s, home:%s, dir:%s, len:%zd, dirlen:%zd",
chrooted, ctrl->cwd, home, dir, strlen(home), strlen(dir));
send_msg(ctrl->sd, "550 No such directory.\r\n");
return;
}
// ...
if (!dir ... so dir might be NULL but will be used in the DBG() macro with a call to strlen(dir). As can be seen from the stack trace dir == $rdi and is NULL (0) at this point which causes the crash. To force dir == NULL we can look at compose_abspath in common.c which calls compose_path here ptr = compose_path(ctrl, path); and return ptr; returns the pointer at the end of the function:
Hi!
I found a bug that crashes the forked child pre-authenticated. The details are as follows:
Triggering the Bug
output of GDB session attached to
uftpd -n /tmp
:registers
rdi
is 0the stack trace is as follows:
the relevant source code in
ftpcmd.c
if (!dir ...
sodir
might beNULL
but will be used in theDBG()
macro with a call tostrlen(dir)
. As can be seen from the stack tracedir == $rdi
and isNULL (0)
at this point which causes the crash. To forcedir == NULL
we can look atcompose_abspath
incommon.c
which callscompose_path
hereptr = compose_path(ctrl, path);
andreturn ptr;
returns the pointer at the end of the function:So we have to look at
compose_path
incommon.h
. The trace that leads todir == NULL
is the following:Best Martin