lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080425125230.GA12343@alice>
Date:	Fri, 25 Apr 2008 14:52:30 +0200
From:	Eric Sesterhenn <snakebyte@....de>
To:	Evgeniy Polyakov <johnpol@....mipt.ru>
Cc:	netdev@...r.kernel.org
Subject: Re: Slab Corruption with ipv6 and tcp6fuzz

* Evgeniy Polyakov (johnpol@....mipt.ru) wrote:
> Hi.
> 
> On Thu, Apr 24, 2008 at 04:27:27PM +0200, Eric Sesterhenn (snakebyte@....de) wrote:
> > i found some local ivp6 network fuzzing tools from the bsd folks
> > today and wanted to add them to my testmachine. When
> > trying one of them (running with user privs) it gave me slab corruption errors.
> > Running http://clem1.be/lf6/tcp6fuzz.c 1 to 5 times
> > always results in errors, strangely using the same seed twice
> > in a row doesnt trigger the warnings again.
> > 
> > If there is any more info i can provide please let me know.
> 
> $ wget http://clem1.be/lf6/tcp6fuzz.c
> --01:09:26--  http://clem1.be/lf6/tcp6fuzz.c
>            => `tcp6fuzz.c'
>  Resolving clem1.be... 88.169.180.107
>  Connecting to clem1.be|88.169.180.107|:80... failed: Connection refused.
> 
> Please post your source here (google can not find it either), if it is
> that easily reproducible, you can be sure, bug will be fixed in a few
> moments.
> 
> > [   57.810370] sock_set_timeout: `tcp6fuzz' (pid 3721) tries to set negative timeout
> > [  215.102729] =============================================================================
> > [  215.102786] BUG skbuff_head_cache: Invalid object pointer 0xccd2b520
> > [  215.102810] -----------------------------------------------------------------------------
> > [  215.102816] 
> > [  215.102840] INFO: Slab 0xc119c560 used=10 fp=0x00000000 flags=0x40000083
> > [  215.102868] Pid: 0, comm: swapper Not tainted 2.6.25-03562-g3dc5063 #23
> > [  215.102880]  [<c0177b57>] slab_err+0x47/0x50
> > [  215.102978]  [<c0177bc7>] ? slab_pad_check+0x67/0xe0
> > [  215.102994]  [<c0177c92>] ? check_slab+0x52/0x80
> > [  215.103010]  [<c0179405>] __slab_free+0x1d5/0x2d0
> > [  215.103024]  [<c0179eb0>] kmem_cache_free+0x80/0xe0
> > [  215.103039]  [<c05d91dc>] ? __kfree_skb+0x3c/0x90
> > [  215.103063]  [<c05d91dc>] ? __kfree_skb+0x3c/0x90
> > [  215.103078]  [<c05d91dc>] __kfree_skb+0x3c/0x90
> > [  215.103090]  [<c05d9249>] kfree_skb+0x19/0x30
> > [  215.103103]  [<c0671e3b>] tcp_v6_do_rcv+0x33b/0xcd0
> 
> So far can you run kernel with debug turned on and provide output of
> gdb ./vmlinux
> l *(tcp_v6_do_rcv+0x33b)

l *(tcp_v6_do_rcv+0x33b)
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) l *(tcp_v6_do_rcv+0x33b)
0xc0671e3b is in tcp_v6_do_rcv (net/ipv6/tcp_ipv6.c:1670).
1665    reset:
1666            tcp_v6_send_reset(sk, skb);
1667    discard:
1668            if (opt_skb)
1669                    __kfree_skb(opt_skb);
1670            kfree_skb(skb);
1671            return 0;
1672    csum_err:
1673            TCP_INC_STATS_BH(TCP_MIB_INERRS);
1674            goto discard;


Here is the programm itself...

Greetings, Eric

 
/*
 * TCP/IPV6 socket fuzzer.
 *
 * Copyright (C) 2006, Clément Lecigne
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/uio.h>

void usage(char *);
void randsoopt(int);
void fs(char *, size_t);
void fc(uint32_t, uint32_t, uint32_t, size_t, char *);
unsigned int randaddr(void);

/*
 * boucle until we hit a valid socket option
 */
void randsoopt(int sock)
{
	unsigned int optval;
	int optlen, optname, level, ret, on = rand() % 2;

	do
	{
		switch (rand() % 4)
		{
			case 0:
				level = IPPROTO_IPV6;
				break;
			case 1:
				level = SOL_SOCKET;
				break;
			case 2:
				level = IPPROTO_TCP;
				break;
			case 3:
				level = rand() & 0xFF;
				break;
		}
		
		if (rand() % 8)
		{
			optlen = rand() & 0xffff;
			optval = randaddr();
		}
		else
		{
		/* 
			* In some cases, kernel excepts that
			* optlen == sizeof (int) and that's
			* the first bound checking.
			*/
			optlen = sizeof (int);
			optval = (unsigned int)&on;
		}
		
		if (rand() % 8)
			optname = rand() % 80;
		else
			optname = rand();
#if 0
		/*
		* anti well know mbufs exhaustion. (FreeBSD)
		*/
		if (optname == 25 || optname == IPV6_IPSEC_POLICY || 
				optname == IPV6_FW_ADD || optname == IPV6_FW_FLUSH
				|| optname == IPV6_FW_DEL || optname == IPV6_FW_ZERO)
			continue;
#endif

		ret = setsockopt(sock, level, optname, (void *)optval, optlen);
	}while(ret == -1);
}

/*
* server fuzzage.
*/
void fs(char *port, size_t ms)
{
	int so, ac, one = 1;
	struct addrinfo *res, hints;
	struct sockaddr_in6 from;
	socklen_t fromlen;
	char *buf;

	struct msghdr m;
	struct cmsghdr *c = NULL;
	struct iovec io;

	
	buf = malloc(ms);
	if (buf == NULL)
	{
		perror(" - malloc");
		return;
	}

	fromlen = sizeof from;
	
	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_INET6;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	getaddrinfo("::1", port, &hints, &res);

	m.msg_name = res->ai_addr;
	m.msg_namelen = res->ai_addrlen;
	m.msg_iov = &io;

	so = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (so == -1){
		perror("sock");
		exit(EXIT_FAILURE);
	}
	
	randsoopt(so);

	if (bind(so, res->ai_addr, res->ai_addrlen) < 0){
		perror("bind");
		exit(EXIT_FAILURE);
	}
	
	if (listen(so, 0) < 0){
		perror("listen");
		exit(EXIT_FAILURE);
	}
		
	while(1)
	{
		randsoopt(so);
		ac = accept(so, (struct sockaddr *)&from, &fromlen);
		if (ac == -1){
			perror("accept");
			continue;	/* warn but continue */
		}
		
		randsoopt(ac);

		/* make ac non-blockant */
		ioctl(ac, FIONBIO, &one);

		/* different receiving ways */
		switch(rand() % 3)
		{
			case 0: /* basic read */
				read(ac, buf, rand() % ms);
				break;
			case 1: /* recvfrom */
				recvfrom(ac, buf, rand() % ms, 0, 
						(struct sockaddr *)&from, &fromlen);
				break;
			case 2: /* recvmsg */
				m.msg_iovlen = (rand() % 2) ? rand() : 1;
				m.msg_controllen = (rand() % 2) ? CMSG_LEN(rand() % ms) : 0;
				if (m.msg_controllen)
				{
					c = (struct cmsghdr *)malloc(m.msg_controllen);
					m.msg_control = c;
					c->cmsg_level = (rand() % 2) ? IPPROTO_IPV6 : rand();
					c->cmsg_type = (rand() % 2) ? rand() % 255 : rand();
					c->cmsg_len = (rand() % 2) ? m.msg_controllen : rand();

				}
				else
				{
					m.msg_control = (rand() % 5) ? NULL : (void*)randaddr();
				}
				m.msg_flags = rand();
				io.iov_len = (rand() % 2) ? rand() : rand() % ms;
				recvmsg(ac, &m, (rand() % 2) ? 0 : rand());
				break;
		}
		close(ac); 
	}
	free(buf);
	freeaddrinfo(res);
}                                  
				
/*
* client fuzzage.
*/
void fc(uint32_t count, uint32_t occ, uint32_t opts, size_t ms, char *port)
{
	int so, j, cc, one = 1;
	uint32_t try;
	u_int32_t i, a;
	struct addrinfo *res, hints;
	char *buf;

	struct msghdr m;
	struct cmsghdr *c = NULL;
	struct iovec io;

	/* XXX: wait server */
	usleep(500);

	buf = malloc(ms);
	if (buf == NULL)
	{
		perror(" - malloc");
		return;
	}

	signal(SIGPIPE, SIG_IGN);
	
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET6;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	getaddrinfo("::1", port, &hints, &res);

	m.msg_name = res->ai_addr;
	m.msg_namelen = res->ai_addrlen;
	m.msg_iov = &io;

	for (i = 0; i < occ; i++)
	{
		printf("%d\n", i);
		try = 0;
		do{
			so = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
			try++;
		}while(so == -1 && count != try);
		
		/* make socket non-blockant */
		ioctl(so, FIONBIO, &one);
		
		try = 0;
		do{
			cc = connect(so, res->ai_addr, res->ai_addrlen);
			try++;
		}while(cc == -1 && count != try);

		randsoopt(so); 

		for (a = 0; a < opts; a++)
		{
			try = 0;
			do
			{
				switch(rand() % 3)
				{
				case 0: 
					cc = write(so, buf, rand() % ms);
					break;
				case 1:
					cc = sendto(so, buf, rand() % ms, MSG_DONTWAIT,
							(struct sockaddr *)&res->ai_addr, res->ai_addrlen);
					break;
				case 2:
					m.msg_iovlen = (rand() % 2) ? rand() : 1;
					m.msg_controllen = (rand() % 2) ? CMSG_LEN(rand() % ms) : 0;
					m.msg_flags = MSG_DONTWAIT;
					if (m.msg_controllen)
					{
						c = (struct cmsghdr *)malloc(m.msg_controllen);
						m.msg_control = c;
						c->cmsg_level = (rand() % 2) ? IPPROTO_IPV6 : rand();
						c->cmsg_type = (rand() % 2) ? rand() % 255 : rand();
						c->cmsg_len = (rand() % 2) ? m.msg_controllen : rand();
					}
					else
					{
						m.msg_control = (rand() % 5) ? NULL : (void*)randaddr();
						m.msg_controllen = (rand() % 2) ? rand() : 0;
					}                    
					io.iov_len = (rand() % 2) ? rand() : rand() % ms;
					cc = sendmsg (so, &m, MSG_DONTWAIT);
				}
				if (c != NULL)
				{
					free(c);
					c = NULL;
				}
				try++;
			}while(cc == -1 && count != try);
		}
		close(so);
	}
	free(buf);
	freeaddrinfo(res);
	return;
}

/*
* return a random address
*/
unsigned int randaddr(void)
{
	int stack;
	char *p = malloc(1);
	unsigned int heap = (unsigned int)p;
	free(p);
	switch (rand() % 4)
	{
		case 0:
			return (heap + (rand() & 0xFFF));
		case 1:
			return ((unsigned int)&stack + (rand() & 0xFFF));
		case 2:
			return (0xc0000000 + (rand() & 0xFFFF));
		case 3:
			return (rand());
	}
	return (0);
}
						
/* 
* usage
*/
void usage(char *prog)
{
	printf("usage: %s [-r seed] [-c sendto-timeout] [-m maxsize]\n"
		"          [-o maxsetsockopt] [-n occ] [-p tcp-port]\n", prog);
	exit(1);
}

int main(int ac, char **av)
{
	int32_t occ, count, opts;
	u_int32_t seed;
	size_t maxsize;
	char c;
	pid_t pid;
	char *port = "5000";
	
	/* default values */
	seed = getpid();
	count = 50;
	occ = 100;
	maxsize = 4096;
	opts = 10;
	
	while ((c = getopt(ac, av, "r:n:c:p:m:o:")) != EOF)
	{
		switch (c)
		{
			case 'r':
				seed = atoi(optarg);
				break;
			case 'n':
				occ = atoi(optarg);
				break;
			case 'c':
				count = atoi(optarg);
				break;
			case 'p':
				port = optarg;
				break;
			case 'm':
				maxsize = atoi(optarg);
				break;
			case 'o':
				opts = atoi(optarg);
				break;
			default:
				usage(av[0]);
				break;
		}
	}

	printf(" + using seed : %d\n", seed);
	srand(seed);

	puts(" + forking.");

	pid = fork();
	switch (pid)
	{
		case -1:
			perror(" - fork");
			exit(EXIT_FAILURE);
		case 0:
			/* client fuzzer */
			fs(port, maxsize);
			break;
		default:
			/* server */
			fc(count, occ, opts, maxsize, port);
			break;
	}

	/* client finished, kill the serv */
	kill(pid, SIGKILL);
	
	puts(" + fuzzing finished, your kernel is alive.");
	exit(EXIT_SUCCESS);
}
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ