All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Sesterhenn <snakebyte@gmx.de>
To: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Cc: netdev@vger.kernel.org
Subject: Re: Slab Corruption with ipv6 and tcp6fuzz
Date: Fri, 25 Apr 2008 14:52:30 +0200	[thread overview]
Message-ID: <20080425125230.GA12343@alice> (raw)
In-Reply-To: <20080424211320.GA13695@2ka.mipt.ru>

* Evgeniy Polyakov (johnpol@2ka.mipt.ru) wrote:
> Hi.
> 
> On Thu, Apr 24, 2008 at 04:27:27PM +0200, Eric Sesterhenn (snakebyte@gmx.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);
}

  reply	other threads:[~2008-04-25 12:52 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-24 14:27 Slab Corruption with ipv6 and tcp6fuzz Eric Sesterhenn
2008-04-24 19:48 ` Ilpo Järvinen
2008-04-24 21:13 ` Evgeniy Polyakov
2008-04-25 12:52   ` Eric Sesterhenn [this message]
2008-04-25 13:09     ` Evgeniy Polyakov
2008-04-26 16:05       ` Evgeniy Polyakov
2008-04-27  6:05         ` David Miller
2008-04-27 13:25           ` Patrick McManus
2008-04-27 15:32             ` Eric Sesterhenn
2008-04-27 16:48         ` Patrick McManus
2008-04-27 22:27           ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080425125230.GA12343@alice \
    --to=snakebyte@gmx.de \
    --cc=johnpol@2ka.mipt.ru \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.