linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Why copy_from/to_user causes KASAN complain?
@ 2016-05-24 16:35 Lifan Su
  0 siblings, 0 replies; only message in thread
From: Lifan Su @ 2016-05-24 16:35 UTC (permalink / raw)
  To: linux-kernel

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;
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-05-24 16:35 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-24 16:35 Why copy_from/to_user causes KASAN complain? Lifan Su

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).