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
| ||
|
Message-ID: <CAK18uZ1yj50niJSxCfQ9xdhiU=6zGXNn+2ii1GgZa2UvVeU6jQ@mail.gmail.com> Date: Tue, 24 May 2016 16:35:35 +0000 From: Lifan Su <thssld@...il.com> To: linux-kernel@...r.kernel.org Subject: Why copy_from/to_user causes KASAN complain? Hi all, I got "BUG: KASAN: user-memory-access on address ..." message when developing a driver. I reviewed my code twice and didn't find why. I experienced this on various kernel versions. Please tell me why my code cause this warning? Here is a minimal reproduce example: On a Fedora-23 host, compile a 4.6 kernel with KASAN enabled with outline (we use GCC-4.8.5 during development). Reboot to use the KASAN-enabled kernel. Compile section KERNEL as a kernel module and modprobe the module. Compile section USER as a userland executable and run the executable. Result (timestamp omitted): test dev : ioctl: cmd: 440074d1, arg: 0000000000601080, local: ff ffffffa018ac60 test dev : ioctl/w: calling copy_from_user ================================================================= BUG: KASAN: user-memory-access on address 0000000000601080 Read of size 1024 by task test_drv_ioctl/946 ...... test dev : ioctl: cmd: 840074d0, arg: 0000000000601080, local: ff ffffffa018ac60 test dev : ioctl/r: calling copy_to_user ================================================================= BUG: KASAN: user-memory-access on address 0000000000601080 Write of size 1024 by task test_drv_ioctl/946 /**************************** KERNEL ****************************/ #define pr_fmt(fmt) "test dev : " fmt #include <linux/module.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/cdev.h> #include <asm-generic/uaccess.h> #include <asm-generic/ioctl.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("FOO"); MODULE_DESCRIPTION("BAR"); #define LEN 1024 #define IOCTL_READ _IOR('t', 0xD0, u8[LEN]) #define IOCTL_WRITE _IOW('t', 0xD1, u8[LEN]) static u8 buf[LEN]; static dev_t major; static struct class *class; static struct cdev cdev; static struct device *cdevice; static long ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long err; void __user *ptr = (void __user *)arg; pr_info("ioctl: cmd: %08x, arg: %p, local: %p\n", cmd, ptr, buf); switch (cmd) { case IOCTL_READ: pr_info("ioctl/r: calling copy_to_user\n"); if (copy_to_user(ptr, buf, LEN)) { pr_info("ioctl/r: failed to copy to user\n"); err = -EFAULT; } else { pr_info("ioctl/r: buffer copied, val: %8ph\n", buf); err = 0; } break; case IOCTL_WRITE: pr_info("ioctl/w: calling copy_from_user\n"); if (copy_from_user(buf, ptr, LEN)) { pr_info("ioctl/w: failed to copy from user\n"); err = -EFAULT; } else { pr_info("ioctl/w: buffer copied, val: %8ph\n", buf); err = 0; } break; default: pr_info("ioctl: invalid command\n"); err = -EINVAL; break; } return err; } static const struct file_operations cdev_ops = { .owner = THIS_MODULE, .unlocked_ioctl = ioctl, }; static int test_init(void) { int rc; pr_info("test device initing\n"); rc = alloc_chrdev_region(&major, 0, 1, "test"); if (rc) { goto fail_alloc_chrdev_region; } pr_info("major assigned: %d\n", (int)MAJOR(major)); class = class_create(THIS_MODULE, "test_ctl"); if (IS_ERR(class)) { pr_err("failed to create class\n"); rc = PTR_RET(class); goto fail_create_class; } cdev_init(&cdev, &cdev_ops); cdev.owner = THIS_MODULE; rc = cdev_add(&cdev, MKDEV(MAJOR(major), 0), 1); if (rc) { pr_info("failed to add char dev\n"); goto fail_cdev_add; } cdevice = device_create(class, NULL, MKDEV(MAJOR(major), 0), NULL, "test_ctl"); if (IS_ERR(cdevice)) { pr_err("failed to create /dev/ file\n"); rc = PTR_RET(cdevice); goto fail_device_create; } pr_info("driver initialized\n"); return 0; device_destroy(class, MKDEV(major, 0)); fail_device_create: cdev_del(&cdev); fail_cdev_add: class_destroy(class); fail_create_class: unregister_chrdev_region(major, 1); fail_alloc_chrdev_region: return rc; } module_init(test_init); /**************************** USER ****************************/ #include <linux/ioctl.h> #include <stdint.h> #include <sys/ioctl.h> #include <fcntl.h> #include <errno.h> #include <stdio.h> #define LEN 1024 #define IOCTL_READ _IOR('t', 0xD0, uint8_t[LEN]) #define IOCTL_WRITE _IOW('t', 0xD1, uint8_t[LEN]) static uint8_t buf[LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; int main() { int ret; int fd = open("/dev/test_ctl", O_RDWR); fprintf(stderr, "buf: %p\n", buf); if (fd == -1) { ret = -errno; fprintf(stderr, "failed to open file: %d\n", ret); goto err; } if (ioctl(fd, IOCTL_WRITE, buf)) { ret = -errno; fprintf(stderr, "failed to call ioctl write: %d\n", ret); goto err; } buf[0] = buf[1] = buf[2] = 0; if(ioctl(fd, IOCTL_READ, buf)) { ret = -errno; fprintf(stderr, "failed to call ioctl read: %d\n", ret); goto err; } fprintf(stderr, "memory: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); err: return ret; }
Powered by blists - more mailing lists