cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hidraw.c (14766B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * HID raw devices, giving access to raw HID events.
      4 *
      5 * In comparison to hiddev, this device does not process the
      6 * hid events at all (no parsing, no lookups). This lets applications
      7 * to work on raw hid events as they want to, and avoids a need to
      8 * use a transport-specific userspace libhid/libusb libraries.
      9 *
     10 *  Copyright (c) 2007-2014 Jiri Kosina
     11 */
     12
     13
     14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     15
     16#include <linux/fs.h>
     17#include <linux/module.h>
     18#include <linux/errno.h>
     19#include <linux/kernel.h>
     20#include <linux/init.h>
     21#include <linux/cdev.h>
     22#include <linux/poll.h>
     23#include <linux/device.h>
     24#include <linux/major.h>
     25#include <linux/slab.h>
     26#include <linux/hid.h>
     27#include <linux/mutex.h>
     28#include <linux/sched/signal.h>
     29#include <linux/string.h>
     30
     31#include <linux/hidraw.h>
     32
     33static int hidraw_major;
     34static struct cdev hidraw_cdev;
     35static struct class *hidraw_class;
     36static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
     37static DECLARE_RWSEM(minors_rwsem);
     38
     39static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
     40{
     41	struct hidraw_list *list = file->private_data;
     42	int ret = 0, len;
     43	DECLARE_WAITQUEUE(wait, current);
     44
     45	mutex_lock(&list->read_mutex);
     46
     47	while (ret == 0) {
     48		if (list->head == list->tail) {
     49			add_wait_queue(&list->hidraw->wait, &wait);
     50			set_current_state(TASK_INTERRUPTIBLE);
     51
     52			while (list->head == list->tail) {
     53				if (signal_pending(current)) {
     54					ret = -ERESTARTSYS;
     55					break;
     56				}
     57				if (!list->hidraw->exist) {
     58					ret = -EIO;
     59					break;
     60				}
     61				if (file->f_flags & O_NONBLOCK) {
     62					ret = -EAGAIN;
     63					break;
     64				}
     65
     66				/* allow O_NONBLOCK to work well from other threads */
     67				mutex_unlock(&list->read_mutex);
     68				schedule();
     69				mutex_lock(&list->read_mutex);
     70				set_current_state(TASK_INTERRUPTIBLE);
     71			}
     72
     73			set_current_state(TASK_RUNNING);
     74			remove_wait_queue(&list->hidraw->wait, &wait);
     75		}
     76
     77		if (ret)
     78			goto out;
     79
     80		len = list->buffer[list->tail].len > count ?
     81			count : list->buffer[list->tail].len;
     82
     83		if (list->buffer[list->tail].value) {
     84			if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
     85				ret = -EFAULT;
     86				goto out;
     87			}
     88			ret = len;
     89		}
     90
     91		kfree(list->buffer[list->tail].value);
     92		list->buffer[list->tail].value = NULL;
     93		list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
     94	}
     95out:
     96	mutex_unlock(&list->read_mutex);
     97	return ret;
     98}
     99
    100/*
    101 * The first byte of the report buffer is expected to be a report number.
    102 */
    103static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
    104{
    105	unsigned int minor = iminor(file_inode(file));
    106	struct hid_device *dev;
    107	__u8 *buf;
    108	int ret = 0;
    109
    110	lockdep_assert_held(&minors_rwsem);
    111
    112	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
    113		ret = -ENODEV;
    114		goto out;
    115	}
    116
    117	dev = hidraw_table[minor]->hid;
    118
    119	if (count > HID_MAX_BUFFER_SIZE) {
    120		hid_warn(dev, "pid %d passed too large report\n",
    121			 task_pid_nr(current));
    122		ret = -EINVAL;
    123		goto out;
    124	}
    125
    126	if (count < 2) {
    127		hid_warn(dev, "pid %d passed too short report\n",
    128			 task_pid_nr(current));
    129		ret = -EINVAL;
    130		goto out;
    131	}
    132
    133	buf = memdup_user(buffer, count);
    134	if (IS_ERR(buf)) {
    135		ret = PTR_ERR(buf);
    136		goto out;
    137	}
    138
    139	if ((report_type == HID_OUTPUT_REPORT) &&
    140	    !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
    141		ret = hid_hw_output_report(dev, buf, count);
    142		/*
    143		 * compatibility with old implementation of USB-HID and I2C-HID:
    144		 * if the device does not support receiving output reports,
    145		 * on an interrupt endpoint, fallback to SET_REPORT HID command.
    146		 */
    147		if (ret != -ENOSYS)
    148			goto out_free;
    149	}
    150
    151	ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
    152				HID_REQ_SET_REPORT);
    153
    154out_free:
    155	kfree(buf);
    156out:
    157	return ret;
    158}
    159
    160static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
    161{
    162	ssize_t ret;
    163	down_read(&minors_rwsem);
    164	ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
    165	up_read(&minors_rwsem);
    166	return ret;
    167}
    168
    169
    170/*
    171 * This function performs a Get_Report transfer over the control endpoint
    172 * per section 7.2.1 of the HID specification, version 1.1.  The first byte
    173 * of buffer is the report number to request, or 0x0 if the device does not
    174 * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
    175 * or HID_INPUT_REPORT.
    176 */
    177static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
    178{
    179	unsigned int minor = iminor(file_inode(file));
    180	struct hid_device *dev;
    181	__u8 *buf;
    182	int ret = 0, len;
    183	unsigned char report_number;
    184
    185	lockdep_assert_held(&minors_rwsem);
    186
    187	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
    188		ret = -ENODEV;
    189		goto out;
    190	}
    191
    192	dev = hidraw_table[minor]->hid;
    193
    194	if (!dev->ll_driver->raw_request) {
    195		ret = -ENODEV;
    196		goto out;
    197	}
    198
    199	if (count > HID_MAX_BUFFER_SIZE) {
    200		hid_warn(dev, "pid %d passed too large report\n",
    201			task_pid_nr(current));
    202		ret = -EINVAL;
    203		goto out;
    204	}
    205
    206	if (count < 2) {
    207		hid_warn(dev, "pid %d passed too short report\n",
    208			task_pid_nr(current));
    209		ret = -EINVAL;
    210		goto out;
    211	}
    212
    213	buf = kmalloc(count, GFP_KERNEL);
    214	if (!buf) {
    215		ret = -ENOMEM;
    216		goto out;
    217	}
    218
    219	/*
    220	 * Read the first byte from the user. This is the report number,
    221	 * which is passed to hid_hw_raw_request().
    222	 */
    223	if (copy_from_user(&report_number, buffer, 1)) {
    224		ret = -EFAULT;
    225		goto out_free;
    226	}
    227
    228	ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
    229				 HID_REQ_GET_REPORT);
    230
    231	if (ret < 0)
    232		goto out_free;
    233
    234	len = (ret < count) ? ret : count;
    235
    236	if (copy_to_user(buffer, buf, len)) {
    237		ret = -EFAULT;
    238		goto out_free;
    239	}
    240
    241	ret = len;
    242
    243out_free:
    244	kfree(buf);
    245out:
    246	return ret;
    247}
    248
    249static __poll_t hidraw_poll(struct file *file, poll_table *wait)
    250{
    251	struct hidraw_list *list = file->private_data;
    252	__poll_t mask = EPOLLOUT | EPOLLWRNORM; /* hidraw is always writable */
    253
    254	poll_wait(file, &list->hidraw->wait, wait);
    255	if (list->head != list->tail)
    256		mask |= EPOLLIN | EPOLLRDNORM;
    257	if (!list->hidraw->exist)
    258		mask |= EPOLLERR | EPOLLHUP;
    259	return mask;
    260}
    261
    262static int hidraw_open(struct inode *inode, struct file *file)
    263{
    264	unsigned int minor = iminor(inode);
    265	struct hidraw *dev;
    266	struct hidraw_list *list;
    267	unsigned long flags;
    268	int err = 0;
    269
    270	if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
    271		err = -ENOMEM;
    272		goto out;
    273	}
    274
    275	down_read(&minors_rwsem);
    276	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
    277		err = -ENODEV;
    278		goto out_unlock;
    279	}
    280
    281	dev = hidraw_table[minor];
    282	if (!dev->open++) {
    283		err = hid_hw_power(dev->hid, PM_HINT_FULLON);
    284		if (err < 0) {
    285			dev->open--;
    286			goto out_unlock;
    287		}
    288
    289		err = hid_hw_open(dev->hid);
    290		if (err < 0) {
    291			hid_hw_power(dev->hid, PM_HINT_NORMAL);
    292			dev->open--;
    293			goto out_unlock;
    294		}
    295	}
    296
    297	list->hidraw = hidraw_table[minor];
    298	mutex_init(&list->read_mutex);
    299	spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
    300	list_add_tail(&list->node, &hidraw_table[minor]->list);
    301	spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
    302	file->private_data = list;
    303out_unlock:
    304	up_read(&minors_rwsem);
    305out:
    306	if (err < 0)
    307		kfree(list);
    308	return err;
    309
    310}
    311
    312static int hidraw_fasync(int fd, struct file *file, int on)
    313{
    314	struct hidraw_list *list = file->private_data;
    315
    316	return fasync_helper(fd, file, on, &list->fasync);
    317}
    318
    319static void drop_ref(struct hidraw *hidraw, int exists_bit)
    320{
    321	if (exists_bit) {
    322		hidraw->exist = 0;
    323		if (hidraw->open) {
    324			hid_hw_close(hidraw->hid);
    325			wake_up_interruptible(&hidraw->wait);
    326		}
    327		device_destroy(hidraw_class,
    328			       MKDEV(hidraw_major, hidraw->minor));
    329	} else {
    330		--hidraw->open;
    331	}
    332	if (!hidraw->open) {
    333		if (!hidraw->exist) {
    334			hidraw_table[hidraw->minor] = NULL;
    335			kfree(hidraw);
    336		} else {
    337			/* close device for last reader */
    338			hid_hw_close(hidraw->hid);
    339			hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
    340		}
    341	}
    342}
    343
    344static int hidraw_release(struct inode * inode, struct file * file)
    345{
    346	unsigned int minor = iminor(inode);
    347	struct hidraw_list *list = file->private_data;
    348	unsigned long flags;
    349
    350	down_write(&minors_rwsem);
    351
    352	spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
    353	list_del(&list->node);
    354	spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
    355	kfree(list);
    356
    357	drop_ref(hidraw_table[minor], 0);
    358
    359	up_write(&minors_rwsem);
    360	return 0;
    361}
    362
    363static long hidraw_ioctl(struct file *file, unsigned int cmd,
    364							unsigned long arg)
    365{
    366	struct inode *inode = file_inode(file);
    367	unsigned int minor = iminor(inode);
    368	long ret = 0;
    369	struct hidraw *dev;
    370	void __user *user_arg = (void __user*) arg;
    371
    372	down_read(&minors_rwsem);
    373	dev = hidraw_table[minor];
    374	if (!dev || !dev->exist) {
    375		ret = -ENODEV;
    376		goto out;
    377	}
    378
    379	switch (cmd) {
    380		case HIDIOCGRDESCSIZE:
    381			if (put_user(dev->hid->rsize, (int __user *)arg))
    382				ret = -EFAULT;
    383			break;
    384
    385		case HIDIOCGRDESC:
    386			{
    387				__u32 len;
    388
    389				if (get_user(len, (int __user *)arg))
    390					ret = -EFAULT;
    391				else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
    392					ret = -EINVAL;
    393				else if (copy_to_user(user_arg + offsetof(
    394					struct hidraw_report_descriptor,
    395					value[0]),
    396					dev->hid->rdesc,
    397					min(dev->hid->rsize, len)))
    398					ret = -EFAULT;
    399				break;
    400			}
    401		case HIDIOCGRAWINFO:
    402			{
    403				struct hidraw_devinfo dinfo;
    404
    405				dinfo.bustype = dev->hid->bus;
    406				dinfo.vendor = dev->hid->vendor;
    407				dinfo.product = dev->hid->product;
    408				if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
    409					ret = -EFAULT;
    410				break;
    411			}
    412		default:
    413			{
    414				struct hid_device *hid = dev->hid;
    415				if (_IOC_TYPE(cmd) != 'H') {
    416					ret = -EINVAL;
    417					break;
    418				}
    419
    420				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
    421					int len = _IOC_SIZE(cmd);
    422					ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
    423					break;
    424				}
    425				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
    426					int len = _IOC_SIZE(cmd);
    427					ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
    428					break;
    429				}
    430
    431				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSINPUT(0))) {
    432					int len = _IOC_SIZE(cmd);
    433					ret = hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT);
    434					break;
    435				}
    436				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGINPUT(0))) {
    437					int len = _IOC_SIZE(cmd);
    438					ret = hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT);
    439					break;
    440				}
    441
    442				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSOUTPUT(0))) {
    443					int len = _IOC_SIZE(cmd);
    444					ret = hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT);
    445					break;
    446				}
    447				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGOUTPUT(0))) {
    448					int len = _IOC_SIZE(cmd);
    449					ret = hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT);
    450					break;
    451				}
    452
    453				/* Begin Read-only ioctls. */
    454				if (_IOC_DIR(cmd) != _IOC_READ) {
    455					ret = -EINVAL;
    456					break;
    457				}
    458
    459				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
    460					int len = strlen(hid->name) + 1;
    461					if (len > _IOC_SIZE(cmd))
    462						len = _IOC_SIZE(cmd);
    463					ret = copy_to_user(user_arg, hid->name, len) ?
    464						-EFAULT : len;
    465					break;
    466				}
    467
    468				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
    469					int len = strlen(hid->phys) + 1;
    470					if (len > _IOC_SIZE(cmd))
    471						len = _IOC_SIZE(cmd);
    472					ret = copy_to_user(user_arg, hid->phys, len) ?
    473						-EFAULT : len;
    474					break;
    475				}
    476
    477				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWUNIQ(0))) {
    478					int len = strlen(hid->uniq) + 1;
    479					if (len > _IOC_SIZE(cmd))
    480						len = _IOC_SIZE(cmd);
    481					ret = copy_to_user(user_arg, hid->uniq, len) ?
    482						-EFAULT : len;
    483					break;
    484				}
    485			}
    486
    487		ret = -ENOTTY;
    488	}
    489out:
    490	up_read(&minors_rwsem);
    491	return ret;
    492}
    493
    494static const struct file_operations hidraw_ops = {
    495	.owner =        THIS_MODULE,
    496	.read =         hidraw_read,
    497	.write =        hidraw_write,
    498	.poll =         hidraw_poll,
    499	.open =         hidraw_open,
    500	.release =      hidraw_release,
    501	.unlocked_ioctl = hidraw_ioctl,
    502	.fasync =	hidraw_fasync,
    503	.compat_ioctl   = compat_ptr_ioctl,
    504	.llseek =	noop_llseek,
    505};
    506
    507int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
    508{
    509	struct hidraw *dev = hid->hidraw;
    510	struct hidraw_list *list;
    511	int ret = 0;
    512	unsigned long flags;
    513
    514	spin_lock_irqsave(&dev->list_lock, flags);
    515	list_for_each_entry(list, &dev->list, node) {
    516		int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
    517
    518		if (new_head == list->tail)
    519			continue;
    520
    521		if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
    522			ret = -ENOMEM;
    523			break;
    524		}
    525		list->buffer[list->head].len = len;
    526		list->head = new_head;
    527		kill_fasync(&list->fasync, SIGIO, POLL_IN);
    528	}
    529	spin_unlock_irqrestore(&dev->list_lock, flags);
    530
    531	wake_up_interruptible(&dev->wait);
    532	return ret;
    533}
    534EXPORT_SYMBOL_GPL(hidraw_report_event);
    535
    536int hidraw_connect(struct hid_device *hid)
    537{
    538	int minor, result;
    539	struct hidraw *dev;
    540
    541	/* we accept any HID device, all applications */
    542
    543	dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
    544	if (!dev)
    545		return -ENOMEM;
    546
    547	result = -EINVAL;
    548
    549	down_write(&minors_rwsem);
    550
    551	for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
    552		if (hidraw_table[minor])
    553			continue;
    554		hidraw_table[minor] = dev;
    555		result = 0;
    556		break;
    557	}
    558
    559	if (result) {
    560		up_write(&minors_rwsem);
    561		kfree(dev);
    562		goto out;
    563	}
    564
    565	dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
    566				 NULL, "%s%d", "hidraw", minor);
    567
    568	if (IS_ERR(dev->dev)) {
    569		hidraw_table[minor] = NULL;
    570		up_write(&minors_rwsem);
    571		result = PTR_ERR(dev->dev);
    572		kfree(dev);
    573		goto out;
    574	}
    575
    576	init_waitqueue_head(&dev->wait);
    577	spin_lock_init(&dev->list_lock);
    578	INIT_LIST_HEAD(&dev->list);
    579
    580	dev->hid = hid;
    581	dev->minor = minor;
    582
    583	dev->exist = 1;
    584	hid->hidraw = dev;
    585
    586	up_write(&minors_rwsem);
    587out:
    588	return result;
    589
    590}
    591EXPORT_SYMBOL_GPL(hidraw_connect);
    592
    593void hidraw_disconnect(struct hid_device *hid)
    594{
    595	struct hidraw *hidraw = hid->hidraw;
    596
    597	down_write(&minors_rwsem);
    598
    599	drop_ref(hidraw, 1);
    600
    601	up_write(&minors_rwsem);
    602}
    603EXPORT_SYMBOL_GPL(hidraw_disconnect);
    604
    605int __init hidraw_init(void)
    606{
    607	int result;
    608	dev_t dev_id;
    609
    610	result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
    611			HIDRAW_MAX_DEVICES, "hidraw");
    612	if (result < 0) {
    613		pr_warn("can't get major number\n");
    614		goto out;
    615	}
    616
    617	hidraw_major = MAJOR(dev_id);
    618
    619	hidraw_class = class_create(THIS_MODULE, "hidraw");
    620	if (IS_ERR(hidraw_class)) {
    621		result = PTR_ERR(hidraw_class);
    622		goto error_cdev;
    623	}
    624
    625        cdev_init(&hidraw_cdev, &hidraw_ops);
    626	result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
    627	if (result < 0)
    628		goto error_class;
    629
    630	pr_info("raw HID events driver (C) Jiri Kosina\n");
    631out:
    632	return result;
    633
    634error_class:
    635	class_destroy(hidraw_class);
    636error_cdev:
    637	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
    638	goto out;
    639}
    640
    641void hidraw_exit(void)
    642{
    643	dev_t dev_id = MKDEV(hidraw_major, 0);
    644
    645	cdev_del(&hidraw_cdev);
    646	class_destroy(hidraw_class);
    647	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
    648
    649}