#define _GNU_SOURCE /* dlsym */
#include <stdio.h> /* printf */
#include <sys/stat.h> /* stat */
#include <stdlib.h> /* exit */
#include <unistd.h> /* __xstat, __fxstat */
#include <dlfcn.h> /* dlsym and friends */
#include <sys/mman.h> /* mmap */
#include <string.h> /* memset */
#include <fcntl.h> /* open */
#define FUZZ_TARGET "fuzzme"
#define INPUT_SZ_ADDR 0x1336000
#define INPUT_ADDR 0x1337000
#define MAX_INPUT_SZ (1024 * 1024)
#define TEST_FILE "/bin/ed"
struct
stat st;
FILE
*faked_fp = NULL;
typedef
int
(*__xstat_t)(
int
__ver,
const
char
*__filename,
struct
stat *__stat_buf);
__xstat_t real_xstat = NULL;
typedef
FILE
* (*fopen_t)(
const
char
* pathname,
const
char
* mode);
fopen_t real_fopen = NULL;
typedef
FILE
* (*fopen64_t)(
const
char
* pathname,
const
char
* mode);
fopen64_t real_fopen64 = NULL;
typedef
int
(*__fxstat_t)(
int
__ver,
int
__filedesc,
struct
stat *__stat_buf);
__fxstat_t real_fxstat = NULL;
typedef
int
(*fcntl_t)(
int
fildes,
int
cmd, ...);
fcntl_t real_fcntl = NULL;
static
void
*_resolve_symbol(
const
char
*symbol) {
dlerror();
void
* addr = dlsym(RTLD_NEXT, symbol);
char
* err = NULL;
err = dlerror();
if
(err) {
addr = NULL;
printf
(
"** Err resolving '%s' addr: %s\n"
, symbol, err);
exit
(-1);
}
return
addr;
}
int
__xstat(
int
__ver,
const
char
* __filename,
struct
stat* __stat_buf) {
if
(!real_xstat) {
real_xstat = _resolve_symbol(
"__xstat"
);
}
int
ret = -1;
if
(0x1337 == __ver) {
__ver = 1;
ret = real_xstat(__ver, __filename, __stat_buf);
real_xstat = NULL;
return
ret;
}
if
(!
strcmp
(__filename, FUZZ_TARGET)) {
st.st_size = *(
size_t
*)INPUT_SZ_ADDR;
memcpy
(__stat_buf, &st,
sizeof
(
struct
stat));
ret = 0;
}
else
{
ret = real_xstat(__ver, __filename, __stat_buf);
}
return
ret;
}
FILE
*
fopen
(
const
char
* pathname,
const
char
* mode) {
printf
(
"** fopen() called for '%s'\n"
, pathname);
exit
(0);
}
FILE
* fopen64(
const
char
* pathname,
const
char
* mode) {
if
(NULL == real_fopen64) {
real_fopen64 = _resolve_symbol(
"fopen64"
);
}
FILE
* ret = NULL;
if
(!
strcmp
(FUZZ_TARGET, pathname)) {
if
(
strcmp
(mode,
"r"
)) {
printf
(
"** Attempt to open fuzz-target in illegal mode: '%s'\n"
, mode);
exit
(-1);
}
ret = fmemopen((
void
*)INPUT_ADDR, *(
size_t
*)INPUT_SZ_ADDR, mode);
if
(faked_fp) {
printf
(
"** Attempting to fopen64() fuzzing target more than once\n"
);
exit
(-1);
}
faked_fp = ret;
ret->_fileno = 1337;
}
else
{
ret = real_fopen64(pathname, mode);
}
return
ret;
}
int
__fxstat (
int
__ver,
int
__filedesc,
struct
stat *__stat_buf) {
if
(NULL == real_fxstat) {
real_fxstat = _resolve_symbol(
"__fxstat"
);
}
int
ret = -1;
if
(1337 == __filedesc) {
st.st_size = *(
size_t
*)INPUT_SZ_ADDR;
memcpy
(__stat_buf, &st,
sizeof
(
struct
stat));
ret = 0;
}
else
{
ret = real_fxstat(__ver, __filedesc, __stat_buf);
}
return
ret;
}
int
fcntl(
int
fildes,
int
cmd, ...) {
if
(NULL == real_fcntl) {
real_fcntl = _resolve_symbol(
"fcntl"
);
}
if
(fildes == 1337) {
return
O_RDONLY;
}
else
{
printf
(
"** fcntl() called for real file descriptor\n"
);
exit
(0);
}
}
static
void
_create_mem_mappings(
void
) {
void
*result = NULL;
result = mmap(
(
void
*)(INPUT_SZ_ADDR),
sizeof
(
size_t
),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0,
0
);
if
((MAP_FAILED == result) || (result != (
void
*)INPUT_SZ_ADDR)) {
printf
(
"** Err mapping INPUT_SZ_ADDR, mapped @ %p\n"
, result);
exit
(-1);
}
*(
size_t
*)INPUT_SZ_ADDR = 0;
result = mmap(
(
void
*)(INPUT_ADDR),
(
size_t
)(MAX_INPUT_SZ),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0,
0
);
if
((MAP_FAILED == result) || (result != (
void
*)INPUT_ADDR)) {
printf
(
"** Err mapping INPUT_ADDR, mapped @ %p\n"
, result);
exit
(-1);
}
memset
((
void
*)INPUT_ADDR, 0, (
size_t
)MAX_INPUT_SZ);
}
static
void
_setup_stat_struct(
void
) {
int
result = __xstat(0x1337, FUZZ_TARGET, &st);
if
(-1 == result) {
printf
(
"** Err creating stat struct for '%s' during load\n"
, FUZZ_TARGET);
}
}
#ifdef TEST
static
void
_test_func(
void
) {
int
fd = open(TEST_FILE, O_RDONLY);
if
(-1 == fd) {
printf
(
"** Failed to open '%s' during test\n"
, TEST_FILE);
exit
(-1);
}
ssize_t bytes = read(fd, (
void
*)INPUT_ADDR, (
size_t
)MAX_INPUT_SZ);
close(fd);
*(
size_t
*)INPUT_SZ_ADDR = (
size_t
)bytes;
}
#endif
__attribute__((constructor))
static
void
_hook_load(
void
) {
_create_mem_mappings();
_setup_stat_struct();
#ifdef TEST
_test_func();
#endif
}