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-next>] [day] [month] [year] [list]
Date:	Mon, 23 Feb 2009 15:22:13 +0100
From:	Eric Sesterhenn <snakebyte@....de>
To:	netdev@...r.kernel.org
Subject: VM_BUG_ON triggered with udp6fuzz

hi,

first of all, i am not able to replicate this after a clean boot,
running the command sudo -u snakebyte lf6/udp6fuzz -n 100 -r 9343
produced the following BUG on my test box
Not sure where the get_page was triggered from, could not 
find it in udp6.c ...

[ 7410.317001] ------------[ cut here ]------------
[ 7410.317033] Kernel BUG at c0683663 [verbose debug info unavailable]
[ 7410.317033] invalid opcode: 0000 [#1] PREEMPT DEBUG_PAGEALLOC
[ 7410.317033] last sysfs file: /sys/class/vc/vcs11/dev
[ 7410.317033] Modules linked in: [last unloaded: rcutorture]
[ 7410.317033] 
[ 7410.317033] Pid: 9343, comm: udp6fuzz Not tainted (2.6.29-rc6 #7)
System Name
[ 7410.317033] EIP: 0060:[<c0683663>] EFLAGS: 00010246 CPU: 0
[ 7410.317033] EIP is at ip6_append_data+0x7df/0x9d5
[ 7410.317033] EAX: 00000000 EBX: 00000000 ECX: 00000004 EDX: c12668a0
[ 7410.317033] ESI: c47889ec EDI: cd5319a0 EBP: cbc2ccc4 ESP: cbc2cc70
[ 7410.317033]  DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
[ 7410.317033] Process udp6fuzz (pid: 9343, ti=cbc2c000 task=c4630000
task.ti=cbc2c000)
[ 7410.317033] Stack:
[ 7410.317033]  cbc2cf50 c063fbf2 cd434000 00000000 00000028 00000000
00000010 00004034
[ 7410.317033]  00000000 cbc2cc9c c013e492 cbc2cca8 c12668a0 00000cee
00004028 00000000
[ 7410.317033]  00000000 00000002 00000cee cbc2cf34 cd434000 cbc2cdb4
c0693ba6 00000cee
[ 7410.317033] Call Trace:
[ 7410.317033]  [<c063fbf2>] ? ip_generic_getfrag+0x0/0x8f
[ 7410.317033]  [<c013e492>] ? trace_hardirqs_on+0xb/0xd
[ 7410.317033]  [<c0693ba6>] ? udpv6_sendmsg+0x751/0x9ee
[ 7410.317033]  [<c013fc3d>] ? __lock_acquire+0x6a8/0x6fe
[ 7410.317033]  [<c0106d88>] ? native_sched_clock+0x41/0x68
[ 7410.317033]  [<c012582c>] ? local_bh_enable_ip+0xa0/0xb8
[ 7410.317033]  [<c013e449>] ? trace_hardirqs_on_caller+0x10d/0x14b
[ 7410.317033]  [<c0613b8c>] ? release_sock+0xb1/0xb9
[ 7410.317033]  [<c013e492>] ? trace_hardirqs_on+0xb/0xd
[ 7410.317033]  [<c012582c>] ? local_bh_enable_ip+0xa0/0xb8
[ 7410.317033]  [<c065e0d7>] ? inet_sendmsg+0x3b/0x48
[ 7410.317033]  [<c061218f>] ? sock_sendmsg+0xc9/0xe0
[ 7410.317033]  [<c013bcfd>] ? put_lock_stats+0xd/0x21
[ 7410.317033]  [<c01315c9>] ? autoremove_wake_function+0x0/0x30
[ 7410.317033]  [<c013fdba>] ? lock_release_non_nested+0xb0/0x1f8
[ 7410.317033]  [<c0174812>] ? might_fault+0x4a/0x86
[ 7410.317033]  [<c0174812>] ? might_fault+0x4a/0x86
[ 7410.317033]  [<c0612a88>] ? sys_sendto+0xa4/0xc3
[ 7410.317033]  [<c0106d88>] ? native_sched_clock+0x41/0x68
[ 7410.317033]  [<c013bcfd>] ? put_lock_stats+0xd/0x21
[ 7410.317033]  [<c013bdb0>] ? lock_release_holdtime+0x9f/0xa7
[ 7410.317033]  [<c013fdba>] ? lock_release_non_nested+0xb0/0x1f8
[ 7410.317033]  [<c0174812>] ? might_fault+0x4a/0x86
[ 7410.317033]  [<c06131d7>] ? sys_socketcall+0xe6/0x17b
[ 7410.317033]  [<c0102dc1>] ? sysenter_do_call+0x12/0x31
[ 7410.317033] Code: 74 02 0c 8b 55 dc 3b 16 0f 84 e9 00 00 00 66 83 fb
12 0f 84 d6 00 00 00 8b 55 dc f6 42 01 40 74 03 8b 52 0c 8b 42 04 85 c0
75 04 <0f> 0b eb fe ff 42 04 8b 75 b4 6b 55 b8 0c 8b 87 94 00 00 00 8b 
[ 7410.317033] EIP: [<c0683663>] ip6_append_data+0x7df/0x9d5 SS:ESP
0068:cbc2cc70
[ 7410.408156] ---[ end trace 228f803a591a2d43 ]---


0xc0683663 is in ip6_append_data (include/linux/mm.h:302).
297	}
298	
299	static inline void get_page(struct page *page)
300	{
301		page = compound_head(page);
302		VM_BUG_ON(atomic_read(&page->_count) == 0);
303		atomic_inc(&page->_count);
304	}
305	
306	static inline struct page *virt_to_head_page(const void *x)


The fuzzer used:

---------------------------8<-----------------------------
/*
 * UDP/IPv6 or UDP/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 <sys/param.h>
#include <net/if.h>
//#include <net/if_var.h>
#include <sys/uio.h>
//#include <netinet6/ip6_mroute.h>
//#include <netinet6/in6_var.h>


#define SIOCGETMIFCNT_IN6       SIOCPROTOPRIVATE        /* IP protocol privates */
#define SIOCGETSGCNT_IN6        (SIOCPROTOPRIVATE+1)
#define SIOCGETRPF      (SIOCPROTOPRIVATE+2)

unsigned int randaddr(void);
void randsoopt(int);
void randgoopt(int);
void randioctl(int);
void usage(char *);
void fuzzlog(char *func, char *fmt, ...);

unsigned int count = 0;

/*
 * 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() % 5)
		{
			case 0:
				level = IPPROTO_IPV6;
				break;
			case 1:
				level = SOL_SOCKET;
				break;
			case 2:
				level = IPPROTO_UDP;
				break;
			case 3:
				level = rand() & 0xFF;
				break;
			case 4:
				level = IPPROTO_IP;
				break;
		}
		
		if (rand() % 6)
		{
			optlen = rand();
			optval = (unsigned int)randaddr();
		}
		else
		{
		/* 
			* In some cases, kernel excepts that
			* optlen == sizeof (int) and that's
			* generally the first bound checking.
			*/
			optlen = sizeof (int);
			on = rand();
			optval = (unsigned int)&on;
		}
		
		if (rand() % 8)
			optname = rand() % 255;
		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);
}


/*
* ioctl fuzzer.
*/
void randioctl(int sock)
{
	unsigned long reqs[] = { SIOCGETSGCNT_IN6, SIOCGETMIFCNT_IN6,
		SIOCGETRPF};
/*		SIOCGSCOPE6DEF, SIOCGLIFADDR, SIOCSIFPHYADDR_IN6, SIOCGIFNETMASK_IN6,
		SIOCAIFADDR_IN6, SIOCGIFDSTADDR_IN6, SIOCSIFALIFETIME_IN6, 
		SIOCGIFADDR_IN6, SIOCGIFDSTADDR_IN6, SIOCGIFNETMASK_IN6, SIOCGIFAFLAG_IN6,
		SIOCGIFSTAT_IN6, SIOCGIFSTAT_ICMP6, SIOCGIFALIFETIME_IN6, SIOCSIFALIFETIME_IN6,
		SIOCAIFADDR_IN6, SIOCDIFADDR_IN6 }; */
	unsigned int arg;
	int ret;
	unsigned long request;
	
	if (rand() % 8)
		request = reqs[rand() % (sizeof (reqs) / sizeof (reqs[0]))];
	else
		request = rand() + rand();
	if (rand() % 2)
	{
		arg = randaddr();
		ret = ioctl(sock, request, (caddr_t)arg);
	}
	else
	{
		arg = rand();
		ret = ioctl(sock, request, (int)arg);
	}
}


/*
* return a possible random mapped address
*/
unsigned int randaddr(void)
{
	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)&heap + (rand() & 0xFFF));
		case 2:
			return (0xc0000000 + (rand() & 0xFFFF));
		case 3:
			return (rand());
	}
	return (0);
}


int main(int ac, char **av) 
{
	int32_t cc, s, occ, i, j, try, count, opts;
	u_int32_t seed, maxsize;
	u_int8_t ip6;
	char c, *buf, *port = "1337";
	struct addrinfo *res, hints;
	struct sockaddr_in6 from;
	socklen_t fromlen;
	struct msghdr msg;
	struct cmsghdr *cmsg = NULL;
	struct iovec iov;
	
	/* default values */
	seed = getpid();
	count = 50;
	occ = 1000;
	maxsize = 4096;
	opts = 50;
	ip6 = 1;
	fromlen = sizeof(from);
	
	while ((c = getopt(ac, av, "r:n:c:p:m:o:f:l:46")) != EOF)
	{
		switch (c)
		{
			case '6':
				ip6 = 1;
				break;
			case '4':
				ip6 = 0;
				break;
			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("seeding with %u\n", seed);
	srand(seed);

	buf = malloc(maxsize);
	if (buf == NULL)
	{
		printf("%s: out of memory.\n", av[0]);
		exit(1);
	}

	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	
	if(ip6)
	{
		hints.ai_family = AF_INET6;
		getaddrinfo("::1", port, &hints, &res);
	}
	else
	{
		hints.ai_family = AF_INET;
		getaddrinfo("127.0.0.1", port, &hints, &res);
	}

	for (i = 0; i < occ; i++)
	{
		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
		cc = bind(s, res->ai_addr, res->ai_addrlen);


		for (j = 0; j < opts; j++)
		{
			randsoopt(s);
			randioctl(s);

			try = 0;
			do
			{
				switch(rand() % 3)
				{
				case 0:
					cc = sendto(s, &buf, rand() % maxsize, rand() % 8,
							(struct sockaddr *)res->ai_addr, res->ai_addrlen);
					break;
				case 1:
				case 2:
					msg.msg_controllen = (rand() % 2) ? rand() & maxsize : 0;
					if (msg.msg_controllen)
					{
						if (msg.msg_controllen < sizeof (struct cmsghdr))
							cmsg = (struct cmsghdr *)malloc(sizeof (struct cmsghdr));
						else
							cmsg = (struct cmsghdr *)malloc(msg.msg_controllen);
						if (cmsg == NULL) goto nocmsghdr;
						msg.msg_control = cmsg;
						cmsg->cmsg_level = (rand() % 2) ? IPPROTO_IPV6 : rand();
						cmsg->cmsg_type = (rand() % 2) ? rand() % 255 : rand();
						cmsg->cmsg_len = (rand() % 2) ? msg.msg_controllen : rand();
					}
					else
					{
nocmsghdr:
						msg.msg_control = (rand() % 5) ? NULL : (void*)randaddr();
						msg.msg_controllen = (rand() % 2) ? rand() : 0;
					}
					iov.iov_len = (rand() % 2) ? rand() : rand() & maxsize;
					iov.iov_base = (rand() % 2) ? (void*)randaddr() : &s;
					msg.msg_iov = (rand() % 2) ? (void*)randaddr() : &iov;
					if (rand() % 10)
					{
						msg.msg_name = res->ai_addr;
						msg.msg_namelen = res->ai_addrlen;
					}
					else
					{
						msg.msg_name = (caddr_t)randaddr();
						msg.msg_namelen = rand();
					}
					msg.msg_flags = rand();
					cc = sendmsg (s, &msg, rand());
				}
				if (cmsg != NULL)
				{
					//free(cmsg);
					//cmsg = NULL;
				}
				try++;
			} while(cc == -1 && try != count); 
			recvmsg(s, &msg, MSG_DONTWAIT);
		}
		close(s);
	}
	free(buf);
	freeaddrinfo(res);
	exit(0);
}

/* 
* usage
*/
void usage(char *prog)
{
	printf("usage: %s [-4] [-6] [-r seed] [-c sendto-timeout]\n"
		"          [-m maxsize] [-o maxsetsockopt] [-n occ]\n"
		"          [-p udp-port]\n", prog);
	exit(1);
}
--
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