Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Jan 2007 18:51:03 -0500
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        freebsd-emulation@FreeBSD.org
Subject:   A new mmap finger printer
Message-ID:  <200701191851.08685.jkim@FreeBSD.org>

next in thread | raw e-mail | index | archive | help

--Boundary-00=_slVsFRjAyW28ZgI
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

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

--Boundary-00=_slVsFRjAyW28ZgI
Content-Type: text/plain;
  charset="iso-8859-1";
  name="mmap_test.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="mmap_test.c"

#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);
}

--Boundary-00=_slVsFRjAyW28ZgI--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200701191851.08685.jkim>