Skip to content

Instantly share code, notes, and snippets.

@datenwolf
Last active April 29, 2016 23:50
Show Gist options
  • Save datenwolf/faf828e9facb53929482a94220441a15 to your computer and use it in GitHub Desktop.
Save datenwolf/faf828e9facb53929482a94220441a15 to your computer and use it in GitHub Desktop.
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
/* this is a borken function that exhibits undefined behavior.
* in likely circumstances it will cause the process to crash...
* ... eventually (if it crashes at all)
*/
void crasher(char *p, unsigned i)
{
p[0] = '\n';
memset(p + 1, '.', i + 1);
strcpy(p + i, "crash");
}
int forked_crasher(char *p, size_t sz_p, unsigned i)
{
int status;
/* we somehow have to get the data back to the caller process */
int r_read;
int fd_pipe[2];
size_t p_read = 0;
if( pipe(fd_pipe) ) { return -1; }
/* by fork-ing a new, separate process that's a nearly identical
* clone, with all of the address space and its contents is
* created and starts running. Everything that happens in this
* process, stays in this process (just like Las Vegas) */
pid_t const pid = fork();
if( 0 > pid ) {
close(fd_pipe[0]);
close(fd_pipe[1]);
return -2;
}
if( !pid ) {
/* see pipe(2) for details on how to use a pipe and why we close
* the reading end here. Essentially we don't need it, and keeping
* the reading end open would cause trouble down the line. */
close(fd_pipe[0]);
/* prevent process crashes to create dump file. if we expect a
* crash, then this is desireable, as we don't want to spam
* the working directory with core dump files. */
prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
/* calling the function that may crash */
crasher(p, i);
/* it survived! Hooray \o/ ... now get the result back to parent */
fprintf(stderr, "%u\n", i);
write(fd_pipe[1], p, sz_p);
close(fd_pipe[1]);
/* this process copy has done its deed. Terminate it */
_exit(0);
}
/* close the writing end of the pipe in the parent process. */
close(fd_pipe[1]);
/* read the result back from the child */
do {
do {
r_read = read(fd_pipe[0], (p + p_read), (sz_p - p_read));
} while( 0 > r_read && EAGAIN == errno );
if( 0 < r_read ) {
p_read += r_read;
}
} while( 0 < r_read );
if( 0 == r_read ) {
waitpid(pid, &status, 0);
if( WIFSIGNALED(status) ) {
fprintf(stderr,
"%u: forked crasher terminated with signal %d\n",
i,
(int)WTERMSIG(status) );
}
}
close(fd_pipe[0]);
return 0;
}
void looper(void)
{
unsigned i;
size_t const sz_mem = 0x1000;
char *mem = malloc(sz_mem);
if( !mem ) { return; }
for(i = 0; i < 0x40000; i += 0x100)
{
memset(mem, 0, sz_mem);
forked_crasher(mem, sz_mem, i);
fwrite(mem, strlen(mem), 1, stdout);
}
}
int main(int argc, char *argv[])
{
looper();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment