A new mmap finger printer
Jung-uk Kim
jkim at FreeBSD.org
Sat Jan 20 00:25:52 UTC 2007
I added PROT_EXEC test and cleaned up Marcin Cieslak's mmap finger
printer. Can any one try this on a real Linux/i386 box and send me
the output?
Thanks,
Jung-uk Kim
-------------- next part --------------
#include <errno.h>
#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
struct intdesc {
const int val;
const char *desc;
};
static sigjmp_buf env;
static char nofile[] = "anonymous";
static char testfile[] = "/tmp/test.XXXXXX";
#if defined(__amd64__) || defined(__x86_64__)
static char testfunc[] = {
0x55, /* push %rbp */
0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
0xc7, 0x45, 0xfc,
0x42, 0x00, 0x00, 0x00, /* movl $0x42,-4(%rbp) */
0xc9, /* leaveq */
0xc3 /* retq */
};
#define TOFFSET 7
#elif defined(__i386__)
static char testfunc[] = {
0x55, /* push %ebp */
0x89, 0xe5, /* mov %esp,%ebp */
0x83, 0xec, 0x04, /* sub $0x4,%esp */
0xc7, 0x45, 0xfc,
0x42, 0x00, 0x00, 0x00, /* movl $0x42,-4(%ebp) */
0xc9, /* leave */
0xc3 /* ret */
};
#define TOFFSET 9
#else
#warn "Sorry, this platform is not supported."
#endif
static char *
mmap_test(int map_prot, int map_mode, int fd)
{
char *qp;
qp = mmap(0, 1024, map_prot, map_mode, fd, 0);
if (qp != MAP_FAILED) {
printf("mmap OK ");
return (qp);
} else {
printf("mmap error (%d)", errno);
return (NULL);
}
}
static void
unmap_test(void *ptr)
{
if (ptr != NULL)
munmap(ptr, 1024);
}
static int sigsegv = 0;
static int buserr = 0;
static int othersig = 0;
static void
handle_sig(int sig)
{
switch(sig) {
case SIGSEGV:
sigsegv ++;
break;
case SIGBUS:
buserr ++;
break;
default:
othersig = sig;
}
siglongjmp(env, 1);
}
#define PRINT_SIGNAL() \
do { \
if (sigsegv) \
printf("sigsegv"); \
if (buserr) \
printf("buserr"); \
if (othersig) \
printf("sig%02d", othersig); \
} while(0)
static void
access_test(void *ptr)
{
struct sigaction newsig = {
.sa_handler = &handle_sig,
.sa_flags = 0,
.sa_mask = 0,
};
struct sigaction oldsegv;
struct sigaction oldbus;
char *qp = (char *)ptr;
/* read test */
sigsegv = buserr = othersig = 0;
sigaction(SIGSEGV, &newsig, &oldsegv);
sigaction(SIGBUS, &newsig, &oldbus);
printf("read: ");
if (sigsetjmp(env, 1) == 0)
printf("0x%02x", qp[TOFFSET]);
else
PRINT_SIGNAL();
/* write test */
sigsegv = buserr = othersig = 0;
printf(" write: ");
if (sigsetjmp(env, 1) == 0) {
memcpy(qp, testfunc, sizeof(testfunc));
qp[TOFFSET] = 0x41;
printf("OK");
} else
PRINT_SIGNAL();
/* exec test */
sigsegv = buserr = othersig = 0;
printf(" exec: ");
if (sigsetjmp(env, 1) == 0) {
((void (*)())qp)();
printf("OK");
} else
PRINT_SIGNAL();
sigaction(SIGSEGV, &oldsegv, NULL);
sigaction(SIGBUS, &oldbus, NULL);
}
#undef PRINT_SIGNAL
static void
run_cases(struct intdesc filemodes[], struct intdesc mapmodes[],
struct intdesc mapprots[], char *(*mapfunc)(int, int, int),
void (*accessfunc)(void *), void (*unmapfunc)(void *))
{
struct intdesc *filemode, *map_mode, *map_prot;
int fd, caseid, anon;
void *region;
caseid = 1;
for (filemode = filemodes; filemode->desc != NULL; filemode++) {
for (map_mode = mapmodes; map_mode->desc != NULL; map_mode++) {
for (map_prot = mapprots; map_prot->desc != NULL;
map_prot++) {
if (filemode->desc != nofile) {
anon = 0;
if ((fd = open(testfile,
filemode->val, 0644)) < 0 ) {
perror("open testfile");
return;
}
} else {
fd = -1;
anon = MAP_ANON;
}
printf("%04d: mmap(0, 1024, %s, %s%s, ...)\n"
" for filemode %s: ",
caseid, map_prot->desc,
anon ? "MAP_ANON|" : "",
map_mode->desc,
filemode->desc);
region = (*mapfunc)(map_prot->val,
anon | map_mode->val, fd);
if (region) {
(*accessfunc)(region);
(*unmapfunc)(region);
}
caseid++;
if (fd >= 0)
close(fd);
printf("\n");
}
}
}
}
int
main(void)
{
struct intdesc filemodes[] = {
{O_RDONLY, "O_RDONLY"},
{O_WRONLY, "O_WRONLY"},
{O_RDWR, "O_RDWR"},
{-1, nofile},
{-1, NULL},
};
struct intdesc mapmodes[] = {
#if 0
{0, "none"},
#endif
{MAP_SHARED, "MAP_SHARED"},
{MAP_PRIVATE, "MAP_PRIVATE"},
{-1, NULL},
};
struct intdesc mapprots[] = {
{PROT_NONE, "PROT_NONE"},
{PROT_READ, "PROT_READ"},
{PROT_WRITE, "PROT_WRITE"},
{PROT_EXEC, "PROT_EXEC"},
{PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"},
{PROT_READ|PROT_EXEC, "PROT_READ|PROT_EXEC"},
{PROT_WRITE|PROT_EXEC, "PROT_WRITE|PROT_EXEC"},
{PROT_READ|PROT_WRITE|PROT_EXEC,
"PROT_READ|PROT_WRITE|PROT_EXEC"},
{-1, NULL},
};
int fd;
fd = mkstemp(testfile);
if (fd < 0) {
perror("open testfile");
return (-1);
}
if (write(fd, testfunc, sizeof(testfunc)) != sizeof(testfunc)) {
perror("write testfile");
return (-1);
}
close(fd);
run_cases(filemodes, mapmodes, mapprots, &mmap_test,
&access_test, &unmap_test);
unlink(testfile);
return (0);
}
More information about the freebsd-emulation
mailing list