Created
December 7, 2017 04:02
-
-
Save srikanth007m/374f6047b3b1ed2934408d34fe71e4c2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
C reproducer: | |
// autogenerated by syzkaller (http://github.com/google/syzkaller) | |
#define _GNU_SOURCE | |
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <fcntl.h> | |
#include <linux/if.h> | |
#include <linux/if_ether.h> | |
#include <linux/if_tun.h> | |
#include <linux/ip.h> | |
#include <linux/tcp.h> | |
#include <net/if_arp.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <stdarg.h> | |
#include <stdarg.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdio.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/prctl.h> | |
#include <sys/stat.h> | |
#include <sys/stat.h> | |
#include <sys/syscall.h> | |
#include <sys/time.h> | |
#include <sys/uio.h> | |
#include <sys/wait.h> | |
#include <time.h> | |
#include <unistd.h> | |
__attribute__((noreturn)) static void doexit(int status) | |
{ | |
volatile unsigned i; | |
syscall(__NR_exit_group, status); | |
for (i = 0;; i++) { | |
} | |
} | |
#include <setjmp.h> | |
#include <signal.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <string.h> | |
const int kFailStatus = 67; | |
const int kRetryStatus = 69; | |
static void fail(const char* msg, ...) | |
{ | |
int e = errno; | |
va_list args; | |
va_start(args, msg); | |
vfprintf(stderr, msg, args); | |
va_end(args); | |
fprintf(stderr, " (errno %d)\n", e); | |
doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus); | |
} | |
static __thread int skip_segv; | |
static __thread jmp_buf segv_env; | |
static void segv_handler(int sig, siginfo_t* info, void* uctx) | |
{ | |
uintptr_t addr = (uintptr_t)info->si_addr; | |
const uintptr_t prog_start = 1 << 20; | |
const uintptr_t prog_end = 100 << 20; | |
if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && | |
(addr < prog_start || addr > prog_end)) { | |
_longjmp(segv_env, 1); | |
} | |
doexit(sig); | |
for (;;) { | |
} | |
} | |
static void install_segv_handler() | |
{ | |
struct sigaction sa; | |
memset(&sa, 0, sizeof(sa)); | |
sa.sa_handler = SIG_IGN; | |
syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); | |
syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); | |
memset(&sa, 0, sizeof(sa)); | |
sa.sa_sigaction = segv_handler; | |
sa.sa_flags = SA_NODEFER | SA_SIGINFO; | |
sigaction(SIGSEGV, &sa, NULL); | |
sigaction(SIGBUS, &sa, NULL); | |
} | |
#define NONFAILING(...) \ | |
{ \ | |
__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ | |
if (_setjmp(segv_env) == 0) { \ | |
__VA_ARGS__; \ | |
} \ | |
__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ | |
} | |
static uint64_t current_time_ms() | |
{ | |
struct timespec ts; | |
if (clock_gettime(CLOCK_MONOTONIC, &ts)) | |
fail("clock_gettime failed"); | |
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; | |
} | |
static void vsnprintf_check(char* str, size_t size, const char* format, | |
va_list args) | |
{ | |
int rv; | |
rv = vsnprintf(str, size, format, args); | |
if (rv < 0) | |
fail("tun: snprintf failed"); | |
if ((size_t)rv >= size) | |
fail("tun: string '%s...' doesn't fit into buffer", str); | |
} | |
static void snprintf_check(char* str, size_t size, const char* format, | |
...) | |
{ | |
va_list args; | |
va_start(args, format); | |
vsnprintf_check(str, size, format, args); | |
va_end(args); | |
} | |
#define COMMAND_MAX_LEN 128 | |
#define PATH_PREFIX \ | |
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin " | |
#define PATH_PREFIX_LEN (sizeof(PATH_PREFIX) - 1) | |
static void execute_command(const char* format, ...) | |
{ | |
va_list args; | |
char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN]; | |
int rv; | |
va_start(args, format); | |
memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN); | |
vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, | |
args); | |
rv = system(command); | |
if (rv != 0) | |
fail("tun: command \"%s\" failed with code %d", &command[0], rv); | |
va_end(args); | |
} | |
static int tunfd = -1; | |
static int tun_frags_enabled; | |
#define SYZ_TUN_MAX_PACKET_SIZE 1000 | |
#define MAX_PIDS 32 | |
#define ADDR_MAX_LEN 32 | |
#define LOCAL_MAC "aa:aa:aa:aa:aa:%02hx" | |
#define REMOTE_MAC "bb:bb:bb:bb:bb:%02hx" | |
#define LOCAL_IPV4 "172.20.%d.170" | |
#define REMOTE_IPV4 "172.20.%d.187" | |
#define LOCAL_IPV6 "fe80::%02hxaa" | |
#define REMOTE_IPV6 "fe80::%02hxbb" | |
#define IFF_NAPI 0x0010 | |
#define IFF_NAPI_FRAGS 0x0020 | |
static void initialize_tun(uint64_t pid) | |
{ | |
if (pid >= MAX_PIDS) | |
fail("tun: no more than %d executors", MAX_PIDS); | |
int id = pid; | |
tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK); | |
if (tunfd == -1) { | |
printf( | |
"tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n"); | |
printf("otherwise fuzzing or reproducing might not work as " | |
"intended\n"); | |
return; | |
} | |
char iface[IFNAMSIZ]; | |
snprintf_check(iface, sizeof(iface), "syz%d", id); | |
struct ifreq ifr; | |
memset(&ifr, 0, sizeof(ifr)); | |
strncpy(ifr.ifr_name, iface, IFNAMSIZ); | |
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS; | |
if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) { | |
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; | |
if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) | |
fail("tun: ioctl(TUNSETIFF) failed"); | |
} | |
if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0) | |
fail("tun: ioctl(TUNGETIFF) failed"); | |
tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0; | |
char local_mac[ADDR_MAX_LEN]; | |
snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC, id); | |
char remote_mac[ADDR_MAX_LEN]; | |
snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC, id); | |
char local_ipv4[ADDR_MAX_LEN]; | |
snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, id); | |
char remote_ipv4[ADDR_MAX_LEN]; | |
snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, id); | |
char local_ipv6[ADDR_MAX_LEN]; | |
snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, id); | |
char remote_ipv6[ADDR_MAX_LEN]; | |
snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, id); | |
execute_command("sysctl -w net.ipv6.conf.%s.accept_dad=0", iface); | |
execute_command("sysctl -w net.ipv6.conf.%s.router_solicitations=0", | |
iface); | |
execute_command("ip link set dev %s address %s", iface, local_mac); | |
execute_command("ip addr add %s/24 dev %s", local_ipv4, iface); | |
execute_command("ip -6 addr add %s/120 dev %s", local_ipv6, iface); | |
execute_command("ip neigh add %s lladdr %s dev %s nud permanent", | |
remote_ipv4, remote_mac, iface); | |
execute_command("ip -6 neigh add %s lladdr %s dev %s nud permanent", | |
remote_ipv6, remote_mac, iface); | |
execute_command("ip link set dev %s up", iface); | |
} | |
static void setup_tun(uint64_t pid, bool enable_tun) | |
{ | |
if (enable_tun) | |
initialize_tun(pid); | |
} | |
static int read_tun(char* data, int size) | |
{ | |
if (tunfd < 0) | |
return -1; | |
int rv = read(tunfd, data, size); | |
if (rv < 0) { | |
if (errno == EAGAIN) | |
return -1; | |
if (errno == EBADFD) | |
return -1; | |
fail("tun: read failed with %d", rv); | |
} | |
return rv; | |
} | |
static void flush_tun() | |
{ | |
char data[SYZ_TUN_MAX_PACKET_SIZE]; | |
while (read_tun(&data[0], sizeof(data)) != -1) | |
; | |
} | |
static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2) | |
{ | |
if (a0 == 0xc || a0 == 0xb) { | |
char buf[128]; | |
sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", | |
(uint8_t)a1, (uint8_t)a2); | |
return open(buf, O_RDWR, 0); | |
} else { | |
char buf[1024]; | |
char* hash; | |
NONFAILING(strncpy(buf, (char*)a0, sizeof(buf))); | |
buf[sizeof(buf) - 1] = 0; | |
while ((hash = strchr(buf, '#'))) { | |
*hash = '0' + (char)(a1 % 10); | |
a1 /= 10; | |
} | |
return open(buf, a2, 0); | |
} | |
} | |
static void test(); | |
void loop() | |
{ | |
int iter; | |
for (iter = 0;; iter++) { | |
int pid = fork(); | |
if (pid < 0) | |
fail("clone failed"); | |
if (pid == 0) { | |
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); | |
setpgrp(); | |
flush_tun(); | |
test(); | |
doexit(0); | |
} | |
int status = 0; | |
uint64_t start = current_time_ms(); | |
for (;;) { | |
int res = waitpid(-1, &status, __WALL | WNOHANG); | |
if (res == pid) | |
break; | |
usleep(1000); | |
if (current_time_ms() - start > 5 * 1000) { | |
kill(-pid, SIGKILL); | |
kill(pid, SIGKILL); | |
while (waitpid(-1, &status, __WALL) != pid) { | |
} | |
break; | |
} | |
} | |
} | |
} | |
#ifndef __NR_mmap | |
#define __NR_mmap 222 | |
#endif | |
#ifndef __NR_ioctl | |
#define __NR_ioctl 29 | |
#endif | |
long r[9]; | |
void* thr(void* arg) | |
{ | |
switch ((long)arg) { | |
case 0: | |
r[0] = syscall(__NR_mmap, 0x20000000ul, 0xe26000ul, 0x3ul, 0x32ul, | |
0xfffffffffffffffful, 0x0ul); | |
break; | |
case 1: | |
NONFAILING( | |
memcpy((void*)0x20439000, | |
"\x2f\x64\x65\x76\x2f\x76\x69\x64\x65\x6f\x23\x00", 12)); | |
r[2] = syz_open_dev(0x20439000ul, 0x3fdul, 0x0ul); | |
break; | |
case 2: | |
NONFAILING(*(uint32_t*)0x2000f000 = (uint32_t)0x80000000ff); | |
NONFAILING(*(uint32_t*)0x2000f004 = (uint32_t)0x1); | |
NONFAILING(*(uint32_t*)0x2000f008 = (uint32_t)0x2); | |
NONFAILING(*(uint32_t*)0x2000f00c = (uint32_t)0x0); | |
NONFAILING(*(uint32_t*)0x2000f010 = (uint32_t)0x0); | |
r[8] = syscall(__NR_ioctl, r[2], 0xc0145608ul, 0x2000f000ul); | |
break; | |
} | |
return 0; | |
} | |
void test() | |
{ | |
long i; | |
pthread_t th[6]; | |
memset(r, -1, sizeof(r)); | |
srand(getpid()); | |
for (i = 0; i < 3; i++) { | |
pthread_create(&th[i], 0, thr, (void*)i); | |
usleep(rand() % 10000); | |
} | |
for (i = 0; i < 3; i++) { | |
pthread_create(&th[3 + i], 0, thr, (void*)i); | |
if (rand() % 2) | |
usleep(rand() % 10000); | |
} | |
usleep(rand() % 100000); | |
} | |
int main() | |
{ | |
int i; | |
for (i = 0; i < 20; i++) { | |
if (fork() == 0) { | |
install_segv_handler(); | |
setup_tun(i, true); | |
loop(); | |
return 0; | |
} | |
} | |
sleep(1000000); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment