kvm: warning in kvm_load_guest_fpu

From: Andrey Konovalov
Date: Tue May 09 2017 - 10:04:45 EST


Hi,

I've got the following error report while fuzzing the kernel with syzkaller.

On commit 2868b2513aa732a99ea4a0a6bf10dc93c1f3dac2 (4.11+).

A reproducer and .config are attached.

------------[ cut here ]------------
WARNING: CPU: 0 PID: 4108 at ./arch/x86/include/asm/fpu/internal.h:169
kvm_load_guest_fpu.part.163+0x2a9/0x430
Modules linked in:
CPU: 0 PID: 4108 Comm: a.out Not tainted 4.11.0+ #331
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
task: ffff880068b2c200 task.stack: ffff880069210000
RIP: 0010:copy_kernel_to_fxregs ./arch/x86/include/asm/fpu/internal.h:169
RIP: 0010:__copy_kernel_to_fpregs ./arch/x86/include/asm/fpu/internal.h:459
RIP: 0010:kvm_load_guest_fpu.part.163+0x2a9/0x430 arch/x86/kvm/x86.c:7596
RSP: 0018:ffff8800692176e8 EFLAGS: 00010297
RAX: ffff880068b2c200 RBX: 1ffff1000d242edd RCX: ffff8800696fc5ec
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880068b2d4c5
RBP: ffff8800692177b0 R08: 1ffff1000d242ebf R09: 00000000fffff8f8
R10: 0000000000000000 R11: 0000000000000002 R12: ffff8800696f8000
R13: ffff880069217788 R14: dffffc0000000000 R15: ffff8800696f8000
FS: 00007fb239f787c0(0000) GS:ffff88006ca00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000000002001f000 CR3: 000000006c55a000 CR4: 00000000000026f0
Call Trace:
kvm_load_guest_fpu arch/x86/kvm/x86.c:6737
vcpu_enter_guest arch/x86/kvm/x86.c:6842
vcpu_run arch/x86/kvm/x86.c:7030
kvm_arch_vcpu_ioctl_run+0x1f61/0x4860 arch/x86/kvm/x86.c:7191
kvm_vcpu_ioctl+0x673/0x1120 arch/x86/kvm/../../../virt/kvm/kvm_main.c:2568
vfs_ioctl fs/ioctl.c:45
do_vfs_ioctl+0x1bf/0x1660 fs/ioctl.c:685
SYSC_ioctl fs/ioctl.c:700
SyS_ioctl+0x8f/0xc0 fs/ioctl.c:691
entry_SYSCALL_64_fastpath+0x1f/0xbe arch/x86/entry/entry_64.S:204
RIP: 0033:0x7fb23968bb79
RSP: 002b:00007ffec57db2d8 EFLAGS: 00000202 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007ffec57db480 RCX: 00007fb23968bb79
RDX: 0000000000000000 RSI: 000000000000ae80 RDI: 0000000000000005
RBP: 0000000000400b40 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000000
R13: 00007ffec57db480 R14: 0000000000000000 R15: 0000000000000000
Code: 4e 00 65 ff 0d f9 72 f5 7e e9 5c fe ff ff e8 7f e4 4e 00 31 c0
49 0f ae 8c 24 00 0b 00 00 85 c0 0f 84 35 fe ff ff e8 67 e4 4e 00 <0f>
ff e9 29 fe ff ff e8 5b e4 4e 00 65 ff 05 c4 72 f5 7e 4d 8d
---[ end trace 7a89c6ce24f92b9b ]---
// autogenerated by syzkaller (http://github.com/google/syzkaller)

#ifndef __NR_mmap
#define __NR_mmap 9
#endif
#ifndef __NR_openat
#define __NR_openat 257
#endif
#ifndef __NR_ioctl
#define __NR_ioctl 16
#endif

#define _GNU_SOURCE

#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <arpa/inet.h>
#include <linux/capability.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <linux/kvm.h>
#include <linux/sched.h>
#include <linux/tcp.h>
#include <net/if_arp.h>

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

const int kFailStatus = 67;
const int kErrorStatus = 68;
const int kRetryStatus = 69;

__attribute__((noreturn)) void doexit(int status)
{
volatile unsigned i;
syscall(__NR_exit_group, status);
for (i = 0;; i++) {
}
}

__attribute__((noreturn)) void fail(const char* msg, ...)
{
int e = errno;
fflush(stdout);
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);
}

__attribute__((noreturn)) void exitf(const char* msg, ...)
{
int e = errno;
fflush(stdout);
va_list args;
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, " (errno %d)\n", e);
doexit(kRetryStatus);
}

static int flag_debug;

void debug(const char* msg, ...)
{
if (!flag_debug)
return;
va_list args;
va_start(args, msg);
vfprintf(stdout, msg, args);
va_end(args);
fflush(stdout);
}

__thread int skip_segv;
__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)) {
debug("SIGSEGV on %p, skipping\n", addr);
_longjmp(segv_env, 1);
}
debug("SIGSEGV on %p, exiting\n", addr);
doexit(sig);
for (;;) {
}
}

static void install_segv_handler()
{
struct sigaction sa;
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); \
}

#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)

#define BITMASK_LEN_OFF(type, bf_off, bf_len) \
(type)(BITMASK_LEN(type, (bf_len)) << (bf_off))

#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
if ((bf_off) == 0 && (bf_len) == 0) { \
*(type*)(addr) = (type)(val); \
} else { \
type new_val = *(type*)(addr); \
new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
*(type*)(addr) = new_val; \
}

struct csum_inet {
uint32_t acc;
};

void csum_inet_init(struct csum_inet* csum)
{
csum->acc = 0;
}

void csum_inet_update(struct csum_inet* csum, const uint8_t* data,
size_t length)
{
if (length == 0)
return;

size_t i;
for (i = 0; i < length - 1; i += 2)
csum->acc += *(uint16_t*)&data[i];

if (length & 1)
csum->acc += (uint16_t)data[length - 1];

while (csum->acc > 0xffff)
csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
}

uint16_t csum_inet_digest(struct csum_inet* csum)
{
return ~csum->acc;
}

static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1,
uintptr_t a2, uintptr_t a3,
uintptr_t a4, uintptr_t a5,
uintptr_t a6, uintptr_t a7,
uintptr_t a8)
{
switch (nr) {
default:
return syscall(nr, a0, a1, a2, a3, a4, a5);
}
}

static void setup_main_process()
{
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);
install_segv_handler();

char tmpdir_template[] = "./syzkaller.XXXXXX";
char* tmpdir = mkdtemp(tmpdir_template);
if (!tmpdir)
fail("failed to mkdtemp");
if (chmod(tmpdir, 0777))
fail("failed to chmod");
if (chdir(tmpdir))
fail("failed to chdir");
}

static void loop();

static void sandbox_common()
{
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
setsid();

struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = 128 << 20;
setrlimit(RLIMIT_AS, &rlim);
rlim.rlim_cur = rlim.rlim_max = 1 << 20;
setrlimit(RLIMIT_FSIZE, &rlim);
rlim.rlim_cur = rlim.rlim_max = 1 << 20;
setrlimit(RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &rlim);

unshare(CLONE_NEWNS);
unshare(CLONE_NEWIPC);
unshare(CLONE_IO);
}

static int do_sandbox_none(int executor_pid, bool enable_tun)
{
int pid = fork();
if (pid)
return pid;

sandbox_common();

loop();
doexit(1);
}

long r[8];
void loop()
{
memset(r, -1, sizeof(r));
r[0] = execute_syscall(__NR_mmap, 0x20000000ul, 0x24000ul, 0x3ul,
0x32ul, 0xfffffffffffffffful, 0x0ul, 0, 0, 0);
NONFAILING(memcpy((void*)0x20000ff7,
"\x2f\x64\x65\x76\x2f\x6b\x76\x6d\x00", 9));
r[2] = execute_syscall(__NR_openat, 0xffffffffffffff9cul,
0x20000ff7ul, 0x0ul, 0x0ul, 0, 0, 0, 0, 0);
r[3] = execute_syscall(__NR_ioctl, r[2], 0xae01ul, 0x0ul, 0, 0, 0, 0,
0, 0);
r[4] = execute_syscall(__NR_ioctl, r[3], 0xae41ul, 0x0ul, 0, 0, 0, 0,
0, 0);
NONFAILING(memcpy(
(void*)0x2001f000,
"\x91\xc9\xf5\xef\x81\xe7\x23\x8b\xca\x8f\x51\xc2\x18\x94\x45\x7a"
"\x06\x66\xde\x83\x3f\x19\x7b\x4b\x74\x5e\x44\xa5\xa4\x9b\x63\x66"
"\xc0\x89\x49\x89\xf9\x63\xf9\xd0\xf7\xcc\x3e\x45\x47\xf3\xd4\x73"
"\x61\x50\xf7\x90\x74\x66\x4f\x6a\xa3\x4e\x92\x1d\xc1\x31\xd4\xc8"
"\xdc\x2e\x16\xa3\x62\xdd\xec\x06\x03\x88\xd2\x54\x05\xdc\xee\xad"
"\x74\xeb\x48\xcb\x0e\x19\x43\x6f\xb1\x06\x43\xe8\xad\x7c\x7e\x6d"
"\xc4\xc7\x74\x8a\xc5\x94\x00\x00\x00\x00\xff\xff\xff\xff\xb3\x6e"
"\xa3\x72\x30\x71\x01\xfe\x6a\xc6\x95\x04\xad\xba\x17\x36\x9e\x92"
"\x6c\x02\xc0\x16\x22\x34\x82\x88\xeb\xee\x6f\xb5\x84\xc6\x1f\x04"
"\xd6\x12\x66\x88\x39\x40\x5a\xab\x69\xbf\x41\x38\xe2\x51\x8b\x40"
"\x19\x99\x94\x8e\xcb\x9f\xb1\xf2\x6d\x85\xdc\xc7\x02\xb2\x56\xf6"
"\xf6\xb8\x43\x5b\x19\x19\xcf\xd0\xae\x60\x85\x30\xb0\xc0\x71\xef"
"\xe4\xd6\xd9\xb2\x6c\x6e\x3b\xbc\x7a\x13\xee\xbb\xb6\x34\x50\x22"
"\x89\x0b\x51\x0c\xb5\xbc\x8f\xde\x7d\xb6\xb0\x3d\xa8\x35\x0f\xf1"
"\x31\x64\xd1\x33\x0b\x43\x82\xa0\x28\x07\xdd\x2b\x1b\xaf\x3a\x25"
"\xb7\x0c\x39\x41\x70\x71\x15\x07\xf7\x37\x85\x5a\x41\x5e\xf2\x44"
"\xbb\xbc\x46\x95\x76\xcf\xa3\x4c\x72\x54\x27\x50\x01\x62\x8a\x8a"
"\xf6\x14\x63\xda\xf8\x6d\x86\xd4\xc1\x52\x18\x74\x05\xc2\x41\xe5"
"\x67\x7f\xa8\xf9\x75\x6d\x2c\x5f\xd6\xbb\x33\x45\x5d\xa9\xe1\xbf"
"\xec\xe3\x87\xb6\x0d\xaf\xe0\xe4\xf5\x88\x5e\x8c\x4a\xb7\x0a\x0d"
"\xdc\x10\x6d\x26\x77\xd3\x58\x37\xfa\x52\x9c\xcb\xc3\x84\xcb\xab"
"\xce\x04\x93\x73\x18\x6a\x68\x66\xdb\x11\x44\x26\x66\x0c\xe1\xfc"
"\x7b\x9a\x86\x09\x2b\xed\x07\x4a\x24\x4f\x7a\xe3\xb8\xe9\xaa\x2d"
"\x71\x2c\x5b\xcf\x34\xb7\x30\x34\x41\xe5\x5e\xe3\x07\x44\x50\x95"
"\x1a\x49\xb2\x6d\x10\xd2\xb3\xf0\x7c\x32\xba\xf8\xe8\x5b\x28\xe4"
"\x08\xe7\x76\x11\xe4\x25\x3f\xb7\x9f\xf2\x9c\xd8\x3b\x17\x51\x86"
"\x79\x30\x63\x5c\x12\xa7\x41\x59\xa4\xbc\xb4\x7f\x17\xf4\xbb\xfc"
"\xb4\x25\x0a\x09\x49\x35\xbe\x2b\x89\x60\x67\x2f\x44\xab\x6c\xb4"
"\xdc\x79\xf9\xee\xf6\xa4\xc8\x53\xe3\xbf\x2d\xc8\x6a\x34\xb4\xe5"
"\x2b\xc6\xb2\x03\x1d\x11\x9d\x68\x3c\xea\x49\x82\x64\x88\xf9\xa2"
"\x67\x4d\x27\xaa\x23\x46\x32\x02\x6b\x2b\x40\xf6\x1d\x8a\x9b\xce"
"\x3b\xcc\x25\x95\x42\x09\xae\x42\x99\x34\xa8\xee\x26\x95\x7e\x32"
"\x03\x00\x00\x00\x00\x00\x00\x00\xb6\x88\xe0\x93\x33\xc6\x0a\x8c"
"\x7c\x20\x94\x02\x64\x25\x97\x27\x3b\xaf\x06\xb2\xec\xeb\xd1\x7c"
"\x20\x61\x78\x3f\x14\x05\xf5\x7a\x90\xcd\x92\x5e\xfa\x4d\xd6\x71"
"\x37\xdd\xc4\x5d\x49\xe2\x05\xbd\x4f\x29\x3e\x6e\x7c\x0c\xe2\x68"
"\x9f\x92\xa5\x30\xa6\x11\xfa\x69\xa4\x89\x85\x12\x3a\xf4\x88\x35"
"\x0e\xc0\xc5\x4e\xaa\x1b\xed\x2e\x2a\x6b\xa3\xe2\x89\x04\x1d\x5c"
"\x74\xc4\xf3\x14\x5a\x3b\xf5\x32\xf5\x2d\xd4\x5d\xba\xac\x87\xe7"
"\x63\x5a\x1e\xc5\x23\xa6\x38\x7c\xa9\x68\xf4\x1f\x7f\x1c\x4f\x6b"
"\xb6\xba\xb5\x54\x32\x2e\x87\x28\x00\x7f\x2b\xa5\xd6\xdb\xb7\xb2"
"\xe5\x11\xda\x26\xd4\x60\x3c\x57\x3f\x0e\x4f\x7c\x29\xbd\x24\x05"
"\x12\x1e\x8b\xd8\xef\xd1\x0b\x43\x40\x71\x46\xa1\xb4\x29\xc4\xc5"
"\x72\xc1\xfc\x72\x75\x56\x16\xf3\x5f\xe8\xa5\x61\xfc\x96\x62\x80"
"\xc3\x28\xb0\xd1\x9d\x77\x84\x9d\x82\xd2\x9d\x11\x4d\xf7\x19\x0f"
"\x27\x0c\xeb\xfb\xec\x61\x6b\x5d\x57\x90\x79\x44\xfe\x08\xc6\x21"
"\xe7\xeb\xdc\xd5\x38\x9f\x9a\x89\x57\xac\xb1\xce\x49\x83\x8d\xd0"
"\xb5\xce\xd6\x60\xea\x7e\xf1\x9c\xc2\xac\x5e\x23\x48\xa8\xcb\xb5"
"\x68\xd0\x5a\xf0\x34\xf4\xfb\x1c\xc7\x76\xfc\xab\xa1\x7d\x8b\x75"
"\xea\x8c\x86\x43\x1b\x3c\xf5\x26\xac\x3c\xb9\x90\x53\xa5\xb5\xef"
"\x62\x56\xd3\x00\x71\x9f\xe2\x12\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x6d\x2d\xfb\xa3\xe3\x72\x30\x41\x0a\x3b\x94\x0a\x3e\x08"
"\xd6\x09\x10\xcf\xa0\xcc\x83\x2d\xc4\x2d\x54\x5a\x1d\xb7\x31\x99"
"\x74\xd8\xd3\x15\x06\x00\x19\xf1\xa0\x29\xe3\xc6\x70\x2d\x39\x43"
"\xf1\x54\x56\x3c\x1e\x4e\x68\x5f\x83\x51\xbb\xa4\x45\x13\x8e\x13"
"\x71\xd8\x9e\xeb\x81\xe1\x10\xb6\x85\x0e\xa2\xd9\x1f\xfc\x91\xee"
"\x67\x0b\x53\x94\x32\x4f\x05\x0f\x37\xdd\xad\x51\xc8\x60\xdb\x3c"
"\x4e\x3e\x71\xc3\x04\x12\x12\x7d\xb0\x5e\x0c\x75\x5d\xe0\xe8\x94"
"\xc3\x53\x37\x51\xfa\x2c\x97\x37\xa9\xdc\xd9\x12\x00\xf4\x68\xf2"
"\x09\xa5\x92\xa3\x43\x57\x38\x08\x54\x85\x97\xad\xae\x95\x25\x40"
"\x60\xf8\xcb\x27\x5f\x7d\xa1\x3a\x42\xda\xcc\x5d\x4b\xa7\xc3\xd3"
"\xac\x1f\xf8\xe4\x88\xcd\xab\xc6\x83\xe0\xb5\xa5\x55\x9e\x8c\x33"
"\x59\xd9\x7a\xfb\xce\xa0\x52\xe8\x90\x11\x88\x62\xa0\x27\xec\xcf"
"\x09\x5d\xfd\xc1\xfa\x78\x57\x39\x7c\xf3\x84\xec\xe5\x9a\x09"
"\x06",
1024));
r[6] = execute_syscall(__NR_ioctl, r[4], 0x5000aea5ul, 0x2001f000ul,
0, 0, 0, 0, 0, 0);
r[7] =
execute_syscall(__NR_ioctl, r[4], 0xae80ul, 0, 0, 0, 0, 0, 0, 0);
}
int main()
{
setup_main_process();
int pid = do_sandbox_none(0, false);
int status = 0;
while (waitpid(pid, &status, __WALL) != pid) {
}
return 0;
}

Attachment: .config
Description: Binary data