Ja, da ist der Patch dann tatsächlich dabei ... das hinterläßt mich eben einigermaßen ratlos, woher das nun kommen mag.
Wenn Du das weiter testen möchtest (und würdest), könnte ich noch ein paar andere Patches versuchen, um überhaupt erst mal die Stelle einzukreisen, wo dieses Problem am Ende auftritt. Die "munmap()"-Aufrufe gibt es (nach "grep"-Aussagen) nur an dieser einen Stelle:
Code:
freetz@zbox:~/freetz> grep -n -r munmap source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/seccompsandbox.c:298: allow_nr(__NR_munmap);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/Changelog:247:- Tuning: eliminate 3 mprotect(), 1 munmap() and 1 mmap() system call per
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/Changelog:1328:- Seccomp filter sandbox: missing munmap() -- oops. Did you know that qsort()
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.h:159:void vsf_sysutil_memunmap(void* p_start, unsigned int length);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1146:vsf_sysutil_memunmap(void* p_start, unsigned int length)
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1148: int retval = munmap(p_start, length);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1151: die("munmap"); <<< hier kommt das "500 OOPS: munmap" her
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1156:vsf_sysutil_memunmap_noerror(void* p_start, unsigned int length)
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1158: int retval = munmap(p_start, length);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:18:void vsf_sysutil_memunmap_noerror(void*, unsigned int);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:90: vsf_sysutil_memunmap(p_mmap, map_size);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:116: vsf_sysutil_memunmap_noerror(p_mmap, map_size);
freetz@zbox:~/freetz>
und das ist diese Funktion:
Code:
void vsf_sysutil_memunmap(void* p_start, unsigned int length)
{
int retval = munmap(p_start, length);
if (retval != 0)
{
die("munmap");
}
}
Also kann der Absturz nur beim Aufruf dieser Funktion erfolgen und davon gibt es auch nur genau eine Stelle (im originalen Code, denn der "_noerror"-Fall ist ja von ersten Patch-Versuch):
Code:
freetz@zbox:~/freetz> grep -n -r vsf_sysutil_memunmap source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.h:159:void vsf_sysutil_memunmap(void* p_start, unsigned int length);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1146:vsf_sysutil_memunmap(void* p_start, unsigned int length)
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/sysutil.c:1156:vsf_sysutil_memunmap_noerror(void* p_start, unsigned int length)
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:18:void vsf_sysutil_memunmap_noerror(void*, unsigned int);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:90: vsf_sysutil_memunmap(p_mmap, map_size);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:116: vsf_sysutil_memunmap_noerror(p_mmap, map_size);
freetz@zbox:~/freetz>
Diese Funktion (vsf_sysutil_memunmap) wird dann also wieder genau an einer einzigen anderen Stelle aufgerufen und das ist die Funktion zum Freigeben so eines "secure buffers" in "secbuf.c":
Code:
void
vsf_secbuf_free(char** p_ptr)
{
unsigned int map_size;
unsigned long page_offset;
char* p_mmap = *p_ptr;
unsigned int page_size = vsf_sysutil_getpagesize();
if (p_mmap == 0)
{
return;
}
/* Calculate the actual start of the mmap region */
page_offset = (unsigned long) p_mmap % page_size;
if (page_offset)
{
p_mmap -= page_offset;
}
p_mmap -= page_size;
/* First make the first page readable so we can get the size */
vsf_sysutil_memprotect(p_mmap, page_size, kVSFSysUtilMapProtReadOnly);
/* Extract the mapping size */
map_size = *((unsigned int*)p_mmap);
/* Lose the mapping */
vsf_sysutil_memunmap(p_mmap, map_size);
}
Da kommt der gesamte "vsftpd" also nur dann hin, wenn irgendjemand irgendwo "vsf_secbuf_free" aufruft und das ist genau an zwei Stellen der Fall (eine davon ist die weiter vorne schon erwähnte automatische Freigabe eines alten Mappings):
Code:
freetz@zbox:~/freetz> grep -n -r vsf_secbuf_free source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/filestr.c:57: vsf_secbuf_free(&p_sec_buf);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.h:17:/* vsf_secbuf_free()
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.h:24:void vsf_secbuf_free(char** p_ptr);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:17:void vsf_secbuf_free_noerror(char**);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:30: vsf_secbuf_free_noerror(p_ptr);
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:68:vsf_secbuf_free(char** p_ptr)
source/target-mips_gcc-5.5.0_uClibc-1.0.14-nptl_kernel-3.10/vsftpd-3.0.3/secbuf.c:94:vsf_secbuf_free_noerror(char** p_ptr)
freetz@zbox:~/freetz>
Da bleibt also nur die Stelle, die ich schon gepatcht habe oder die Datei "filestr.c", die so aussieht:
Code:
/*
* Part of Very Secure FTPd
* Licence: GPL v2
* Author: Chris Evans
* filestr.c
*
* This file contains extensions to the string/buffer API, to load a file
* into a buffer.
*/
#include "filestr.h"
/* Get access to "private" functions */
#define VSFTP_STRING_HELPER
#include "str.h"
#include "sysutil.h"
#include "secbuf.h"
#include "utility.h"
int
str_fileread(struct mystr* p_str, const char* p_filename, unsigned int maxsize)
{
int fd;
int retval = 0;
filesize_t size;
char* p_sec_buf = 0;
struct vsf_sysutil_statbuf* p_stat = 0;
/* In case we fail, make sure we return an empty string */
str_empty(p_str);
fd = vsf_sysutil_open_file(p_filename, kVSFSysUtilOpenReadOnly);
if (vsf_sysutil_retval_is_error(fd))
{
return fd;
}
vsf_sysutil_fstat(fd, &p_stat);
if (vsf_sysutil_statbuf_is_regfile(p_stat))
{
size = vsf_sysutil_statbuf_get_size(p_stat);
if (size > maxsize)
{
size = maxsize;
}
vsf_secbuf_alloc(&p_sec_buf, (unsigned int) size);
retval = vsf_sysutil_read_loop(fd, p_sec_buf, (unsigned int) size);
if (vsf_sysutil_retval_is_error(retval))
{
goto free_out;
}
else if ((unsigned int) retval != size)
{
die("read size mismatch");
}
str_alloc_memchunk(p_str, p_sec_buf, (unsigned int) size);
}
free_out:
vsf_sysutil_free(p_stat);
vsf_secbuf_free(&p_sec_buf);
vsf_sysutil_close(fd);
return retval;
}
Diese Funktion liest halt irgendeine Datei in den Speicher als Zeichenkette und benutzt diesen "secure buffer" nur als Zwischenlager (das Ergebnis wird dann mittels "str_alloc_memchunk" in einen anderen Speicherbereich kopiert) - sprich, er wird hinterher bzw. im Falle eines Fehlers auch gleich wieder freigegeben. Dabei kann eigentlich auch kein Problem auftreten ... die einzige Chance wäre eine Datei der Länge 0, die dann auch zum "vsf_secbuf_alloc()" mit Länge 0 führen würde.
Da liegt dann vielleicht auch wieder der Fehler ... eine Behandlung, daß bei Dateilänge 0 der ganze Zinnober nicht stattfindet, ist in "str_fileread()" nicht zu sehen. Das wäre dann also doch noch eine andere Idee (insofern war die Info, daß es mit "anonymous" (der ja nirgendwo in einer "/etc/passwd" o.ä. steht) funktioniert, dann tatsächlich wichtig - wenn es diesmal die Ursache des Problems sein sollte).
Ich baue mal einen Patch für das Umgehen einer Datei der Länge 0 ... jetzt schicke ich das hier aber doch erst mal ab, weil mir ständig irgendein JS-Script etwas von "blocked" erzählen will und ich den bisherigen Text schon gerne gerettet hätte.
EDIT: Das nenne ich mal "overblocking" ... wenn ich oben die Sterne beim FTP-Benutzernamen oder beim Dateinamen in "/etc" weglasse und das "ausschreibe", dann lehnt irgendein dämlicher Content-Checker bei CloudFlare die Übertragung ab.
EDIT2: Nun geht's doch ... und ich wollte noch einen Screenshot machen. :-(
Egal, weiter im Text ... den alten Patch einfach vergessen (Löschen reicht) und ich melde mich, wenn ich einen neuen habe.