/* exploitme coded in a hurry by Yoann Guillot and Julien Tinnes, used 'man select_tut' as skeleton */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/mman.h>
#include <malloc.h>

#define LISTEN_PORT 4545

int	vuln(void) {
	struct sockaddr_in a;
	int s, mysock;
	int yes, ret, pagesize;
	void *buf;

	pagesize = sysconf(_SC_PAGE_SIZE);
	if (pagesize == -1) {
		perror("pagesize");
		return -1;
	}

	if (pagesize < 4096)
		pagesize=(4096/pagesize+1)*pagesize;
	printf("Detected pagesize: %d\n", pagesize);
	buf=memalign(pagesize, pagesize);
	if (buf == NULL) {
		perror("memalign");
		return -1;
	}
	if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
		perror ("socket");
		return -1;
	}
	yes = 1;
	if (setsockopt
			(s, SOL_SOCKET, SO_REUSEADDR,
			 (char *) &yes, sizeof (yes)) < 0) {
		perror ("setsockopt");
		close (s);
		return -1;
	}
	memset (&a, 0, sizeof (a));
	a.sin_port = htons (LISTEN_PORT);
	a.sin_family = AF_INET;
	if (bind
			(s, (struct sockaddr *) &a, sizeof (a)) < 0) {
		perror ("bind");
		close (s);
		return -1;
	}
	printf ("Send your shellcode to port %d\n",
		(int) LISTEN_PORT);
	listen (s, 10);
	for (;;) {
		mysock=accept(s, NULL, NULL);
		if (mysock == -1) {
			perror("accept");
			close(s);
			return -1;
		}
		if (!fork()) {
			printf("Got new connexion\n");
			close(s);
			switch (yes=read(mysock, buf, pagesize)) {
				case -1:
					perror("read");
				case 0:
					close(mysock);
					close(s);
					return -1;
			}
			printf("Read %d bytes\n", yes);
			/* This has the useful side effect of flushing the cache on architectures such as MIPS! */
			ret=mprotect(buf, pagesize, PROT_READ|PROT_WRITE|PROT_EXEC);
			if (ret) {
				perror("mprotect");
				return -1;
			}
			((void (*)())buf)();
			return 42;
		} else
			close(mysock);
	}
	
}

int main(void)
{
#ifdef SWITCH_STACK
	unsigned char *m;
	m = mmap(NULL, 1024 * 1024 * 2, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
	m += (1024 * 1024 * 2) - 4;
	__asm__("movl %0, %%esp; call vuln" : : "m" (m));
#else
	vuln();
#endif
}
