on win32, use a named pipe and IOCP to read stdout, stderr and debugfd correctly.
This commit is contained in:
parent
714c203ece
commit
8349e4746d
@ -65,6 +65,62 @@ static void mydebug(char const *format, va_list args);
|
||||
char debugbuffer[BUFSIZ];
|
||||
size_t debugcount = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
CRITICAL_SECTION _zz_pipe_cs; /* Initialized in DllMain */
|
||||
|
||||
void _zz_debug(char const *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[0x100];
|
||||
DWORD written;
|
||||
va_start(args, format);
|
||||
//if (_zz_debuglevel >= 1) // LATER:
|
||||
{
|
||||
HANDLE dbg_hdl = (HANDLE)_get_osfhandle(_zz_debugfd);
|
||||
int ret = _vsnprintf(buf, sizeof(buf), format, args);
|
||||
|
||||
if (ret <= 0) return; /* if _snprintf failed, we send nothing */
|
||||
if (buf[0] == '\0') return; /* if the buf is empty, we don't bother to send it to zzuf */
|
||||
|
||||
/* FIXME: if len >= count, no null-terminator is appended, so we may erased the last character */
|
||||
if (ret >= sizeof(buf)) buf[ret - 1] = '\n';
|
||||
else buf[ret++] = '\n';
|
||||
|
||||
EnterCriticalSection(&_zz_pipe_cs);
|
||||
WriteFile(dbg_hdl, buf, ret, &written, NULL);
|
||||
LeaveCriticalSection(&_zz_pipe_cs);
|
||||
}
|
||||
va_end(args);
|
||||
fflush(NULL); /* flush all streams to make sure zzuf gotta catch 'em all */
|
||||
}
|
||||
|
||||
void _zz_debug2(char const *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[0x100];
|
||||
DWORD written;
|
||||
va_start(args, format);
|
||||
//if (_zz_debuglevel >= 1) // LATER:
|
||||
{
|
||||
HANDLE dbg_hdl = (HANDLE)_get_osfhandle(_zz_debugfd);
|
||||
int ret = _vsnprintf(buf, sizeof(buf), format, args);
|
||||
|
||||
if (ret <= 0) return; /* if _snprintf failed, we send nothing */
|
||||
if (buf[0] == '\0') return; /* if the buf is empty, we don't bother to send it to zzuf */
|
||||
|
||||
/* FIXME: if len >= count, no null-terminator is appended, so we may erased the last character */
|
||||
if (ret >= sizeof(buf)) buf[ret - 1] = '\n';
|
||||
else buf[ret++] = '\n';
|
||||
|
||||
EnterCriticalSection(&_zz_pipe_cs);
|
||||
WriteFile(dbg_hdl, buf, ret, &written, NULL);
|
||||
LeaveCriticalSection(&_zz_pipe_cs);
|
||||
}
|
||||
va_end(args);
|
||||
fflush(NULL); /* flush all streams to make sure zzuf gotta catch 'em all */
|
||||
}
|
||||
#else
|
||||
void _zz_debug(char const *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -82,6 +138,7 @@ void _zz_debug2(char const *format, ...)
|
||||
mydebug(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Format a string, printf-like, and write the resulting data to zzuf's
|
||||
|
||||
@ -122,8 +122,12 @@ BOOL __stdcall NEW(ReadFile)(HANDLE hFile, LPVOID lpBuffer,
|
||||
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
return ORIG(ReadFile)(hFile, lpBuffer, nNumberOfBytesToRead,
|
||||
BOOL ret;
|
||||
ret = ORIG(ReadFile)(hFile, lpBuffer, nNumberOfBytesToRead,
|
||||
lpNumberOfBytesRead, lpOverlapped);
|
||||
debug("ReadFile(%#08x, %#08x, %#08x, %#08x, %#08x) = %s",
|
||||
hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped, (ret ? "TRUE" : "FALSE"));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -136,7 +140,7 @@ BOOL __stdcall NEW(CloseHandle)(HANDLE hObject)
|
||||
{
|
||||
BOOL ret;
|
||||
ret = ORIG(CloseHandle)(hObject);
|
||||
debug("CloseHandle(%i) = %i", (int)hObject, ret);
|
||||
debug("CloseHandle(%i) = %s", (int)hObject, (ret ? "TRUE" : "FALSE"));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -229,10 +229,12 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, PVOID impLoad)
|
||||
switch(reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
InitializeCriticalSection(&_zz_pipe_cs);
|
||||
_zz_init();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
_zz_fini();
|
||||
DeleteCriticalSection(&_zz_pipe_cs);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -36,3 +36,7 @@ extern void _zz_fini(void) __attribute__((destructor));
|
||||
/* This function is needed to initialise memory functions */
|
||||
extern void _zz_mem_init(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <Windows.h>
|
||||
extern CRITICAL_SECTION _zz_pipe_cs;
|
||||
#endif
|
||||
142
src/myfork.c
142
src/myfork.c
@ -80,50 +80,104 @@ static int dll_inject(PROCESS_INFORMATION *, char const *);
|
||||
static void *get_proc_address(void *, DWORD, char const *);
|
||||
#endif
|
||||
|
||||
int myfork(struct child *child, struct opts *opts)
|
||||
{
|
||||
int pipes[3][2];
|
||||
pid_t pid;
|
||||
int i;
|
||||
|
||||
/* Prepare communication pipe */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
int ret;
|
||||
#if defined HAVE_PIPE
|
||||
ret = pipe(pipes[i]);
|
||||
#elif defined HAVE__PIPE
|
||||
int tmp;
|
||||
/* The pipe is created with NOINHERIT otherwise both parts are
|
||||
* inherited. We then duplicate the part we want. */
|
||||
ret = _pipe(pipes[i], 512, _O_BINARY | O_NOINHERIT);
|
||||
tmp = _dup(pipes[i][1]);
|
||||
close(pipes[i][1]);
|
||||
pipes[i][1] = tmp;
|
||||
#endif
|
||||
if(ret < 0)
|
||||
{
|
||||
perror("pipe");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pid = run_process(child, opts, pipes);
|
||||
if(pid < 0)
|
||||
{
|
||||
/* FIXME: close pipes */
|
||||
fprintf(stderr, "error launching `%s'\n", child->newargv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
child->pid = pid;
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
close(pipes[i][1]);
|
||||
child->fd[i] = pipes[i][0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
int myfork(struct child *child, struct opts *opts)
|
||||
{
|
||||
int pipes[3][2];
|
||||
pid_t pid;
|
||||
int i;
|
||||
|
||||
/* Prepare communication pipe */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
int ret;
|
||||
#if defined HAVE_PIPE
|
||||
ret = pipe(pipes[i]);
|
||||
#elif defined HAVE__PIPE && !defined _WIN32
|
||||
int tmp;
|
||||
/* The pipe is created with NOINHERIT otherwise both parts are
|
||||
* inherited. We then duplicate the part we want. */
|
||||
ret = _pipe(pipes[i], 512, _O_BINARY | O_NOINHERIT);
|
||||
tmp = _dup(pipes[i][1]);
|
||||
close(pipes[i][1]);
|
||||
pipes[i][1] = tmp;
|
||||
#elif defined _WIN32
|
||||
// http://www.daniweb.com/software-development/cpp/threads/295780/using-named-pipes-with-asynchronous-io-redirection-to-winapi
|
||||
{
|
||||
static int pipe_cnt = 0;
|
||||
char pipe_name[BUFSIZ];
|
||||
HANDLE pipe_hdl[2]; /* [0] read | [1] write */
|
||||
HANDLE new_hdl;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = TRUE;
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
|
||||
ret = 0;
|
||||
|
||||
/* Since we have to use a named pipe, we have to make sure the name is unique */
|
||||
_snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\Pipe\\zzuf.%08x.%d", GetCurrentProcessId(), pipe_cnt++);
|
||||
|
||||
/* At this time, the HANDLE is inheritable and can both read/write */
|
||||
if ((pipe_hdl[0] = CreateNamedPipeA(
|
||||
pipe_name,
|
||||
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
1,
|
||||
BUFSIZ,
|
||||
BUFSIZ,
|
||||
0,
|
||||
&sa)) == INVALID_HANDLE_VALUE ||
|
||||
|
||||
/* Create a new handle for writing access only and it must be inheritable */
|
||||
(pipe_hdl[1] = CreateFileA(
|
||||
pipe_name,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
&sa,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
||||
NULL)) == INVALID_HANDLE_VALUE)
|
||||
ret = -1;
|
||||
|
||||
/* Now we create a new handle for the listener which is not inheritable */
|
||||
if (!DuplicateHandle(
|
||||
GetCurrentProcess(), pipe_hdl[0],
|
||||
GetCurrentProcess(), &new_hdl,
|
||||
0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
ret = -1;
|
||||
|
||||
/* Finally we can safetly close the pipe handle */
|
||||
CloseHandle(pipe_hdl[0]);
|
||||
|
||||
/* Now we convert handle to fd */
|
||||
pipes[i][0] = _open_osfhandle((intptr_t)new_hdl, 0x0);
|
||||
pipes[i][1] = _open_osfhandle((intptr_t)pipe_hdl[1], 0x0);
|
||||
}
|
||||
#endif
|
||||
if(ret < 0)
|
||||
{
|
||||
perror("pipe");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pid = run_process(child, opts, pipes);
|
||||
if(pid < 0)
|
||||
{
|
||||
/* FIXME: close pipes */
|
||||
fprintf(stderr, "error launching `%s'\n", child->newargv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
child->pid = pid;
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
close(pipes[i][1]);
|
||||
child->fd[i] = pipes[i][0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined HAVE_SETENV
|
||||
|
||||
103
src/zzuf.c
103
src/zzuf.c
@ -112,6 +112,11 @@ static void usage(void);
|
||||
#define ZZUF_FD_ISSET(fd, p_fdset) \
|
||||
((fd >= 0) && (FD_ISSET(fd, p_fdset)))
|
||||
|
||||
#if defined _WIN32
|
||||
# include <Windows.h>
|
||||
static CRITICAL_SECTION _zz_pipe_cs;
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct opts _opts, *opts = &_opts;
|
||||
@ -123,6 +128,10 @@ int main(int argc, char *argv[])
|
||||
int debug = 0, network = 0;
|
||||
int i;
|
||||
|
||||
#if defined _WIN32
|
||||
InitializeCriticalSection(&_zz_pipe_cs);
|
||||
#endif
|
||||
|
||||
_zz_opts_init(opts);
|
||||
|
||||
for(;;)
|
||||
@ -536,6 +545,10 @@ int main(int argc, char *argv[])
|
||||
_zz_fd_fini();
|
||||
_zz_opts_fini(opts);
|
||||
|
||||
#if defined _WIN32
|
||||
DeleteCriticalSection(&_zz_pipe_cs);
|
||||
#endif
|
||||
|
||||
return opts->crashes ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -914,6 +927,88 @@ static void clean_children(struct opts *opts)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* This structure contains useful information about data sent from fuzzed applications */
|
||||
struct child_overlapped
|
||||
{
|
||||
OVERLAPPED overlapped;
|
||||
char buf[BUFSIZ];
|
||||
struct opts * opts;
|
||||
int child_no;
|
||||
int fd_no;
|
||||
};
|
||||
|
||||
/* This callback is called when fuzzed applications write in fd out, err or debug */
|
||||
static void _stdcall read_child(DWORD err_code, DWORD nbr_of_bytes_transfered, LPOVERLAPPED overlapped)
|
||||
{
|
||||
struct child_overlapped * co = (struct child_overlapped *)overlapped;
|
||||
|
||||
/* TODO: handle more cases like ERROR_MORE_DATA */
|
||||
if (err_code != ERROR_SUCCESS) return;
|
||||
|
||||
EnterCriticalSection(&_zz_pipe_cs);
|
||||
switch (co->fd_no)
|
||||
{
|
||||
case 0: /* debug fd */
|
||||
write(1, "dbg: ", 4);
|
||||
case 1: /* out */
|
||||
write(1, co->buf, nbr_of_bytes_transfered); break;
|
||||
case 2: /* err */
|
||||
write(2, co->buf, nbr_of_bytes_transfered); break;
|
||||
default: break;
|
||||
}
|
||||
LeaveCriticalSection(&_zz_pipe_cs);
|
||||
|
||||
if(co->fd_no != 0) /* either out or err fd */
|
||||
co->opts->child[co->child_no].bytes += nbr_of_bytes_transfered;
|
||||
|
||||
if(co->opts->md5 && co->fd_no == 2)
|
||||
_zz_md5_add(co->opts->child[co->child_no].ctx, co->buf, nbr_of_bytes_transfered);
|
||||
|
||||
free(co); /* clean up allocated data */
|
||||
}
|
||||
|
||||
/* Since on windows select doesn't support file HANDLE, we use IOCP */
|
||||
static void read_children(struct opts *opts)
|
||||
{
|
||||
size_t i, j;
|
||||
HANDLE *children_handle, * cur_child_handle;
|
||||
size_t fd_number = opts->maxchild * 3;
|
||||
|
||||
cur_child_handle = children_handle = malloc(sizeof(*children_handle) * fd_number);
|
||||
|
||||
for(i = 0; i < fd_number; i++)
|
||||
children_handle[i] = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* XXX: cute (i, j) iterating hack */
|
||||
for(i = 0, j = 0; i < (size_t)opts->maxchild; i += (j == 2), j = (j + 1) % 3)
|
||||
{
|
||||
struct child_overlapped * co;
|
||||
HANDLE h;
|
||||
|
||||
if(opts->child[i].status != STATUS_RUNNING)
|
||||
continue;
|
||||
|
||||
co = malloc(sizeof(*co));
|
||||
ZeroMemory(co, sizeof(*co));
|
||||
*cur_child_handle = co->overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
co->child_no = i;
|
||||
co->fd_no = j;
|
||||
co->opts = opts;
|
||||
|
||||
h = (HANDLE)_get_osfhandle(opts->child[i].fd[j]);
|
||||
|
||||
/* FIXME: handle error */
|
||||
ReadFileEx(h, co->buf, sizeof(co->buf), (LPOVERLAPPED)co, read_child);
|
||||
cur_child_handle++;
|
||||
}
|
||||
|
||||
/* FIXME: handle error */
|
||||
WaitForMultipleObjectsEx(fd_number, children_handle, FALSE, INFINITE, TRUE);
|
||||
}
|
||||
|
||||
#else
|
||||
static void read_children(struct opts *opts)
|
||||
{
|
||||
struct timeval tv;
|
||||
@ -933,15 +1028,12 @@ static void read_children(struct opts *opts)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000;
|
||||
|
||||
#if !defined _WIN32
|
||||
/* Win32 does not support select() on non-sockets */
|
||||
errno = 0;
|
||||
ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
|
||||
if(ret < 0 && errno)
|
||||
perror("select");
|
||||
if(ret <= 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* XXX: cute (i, j) iterating hack */
|
||||
for(i = 0, j = 0; i < opts->maxchild; i += (j == 2), j = (j + 1) % 3)
|
||||
@ -951,10 +1043,8 @@ static void read_children(struct opts *opts)
|
||||
if(opts->child[i].status != STATUS_RUNNING)
|
||||
continue;
|
||||
|
||||
#if !defined _WIN32
|
||||
if(!ZZUF_FD_ISSET(opts->child[i].fd[j], &fdset))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
ret = read(opts->child[i].fd[j], buf, BUFSIZ - 1);
|
||||
if(ret > 0)
|
||||
@ -968,7 +1058,6 @@ static void read_children(struct opts *opts)
|
||||
else if(!opts->quiet || j == 0)
|
||||
write((j < 2) ? STDERR_FILENO : STDOUT_FILENO, buf, ret);
|
||||
}
|
||||
#if !defined _WIN32
|
||||
else if(ret == 0)
|
||||
{
|
||||
/* End of file reached */
|
||||
@ -980,9 +1069,9 @@ static void read_children(struct opts *opts)
|
||||
&& opts->child[i].fd[2] == -1)
|
||||
opts->child[i].status = STATUS_EOF;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_SETENV
|
||||
static void setenv(char const *name, char const *value, int overwrite)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user