Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e57480b authored by Jiri Kosina's avatar Jiri Kosina
Browse files

HID: remove BKL from hidraw



Remove BKL from hidraw, which is possible through fixing the
locking of minors_lock mutex properly -- it is now used to
guard all accessess to hidraw_table[], preventing it to becoming
NULL unexpectedly by unregistering the device.

Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 39710479
Loading
Loading
Loading
Loading
+25 −16
Original line number Original line Diff line number Diff line
@@ -105,38 +105,48 @@ out:
static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
{
	unsigned int minor = iminor(file->f_path.dentry->d_inode);
	unsigned int minor = iminor(file->f_path.dentry->d_inode);
	/* FIXME: What stops hidraw_table going NULL */
	struct hid_device *dev;
	struct hid_device *dev = hidraw_table[minor]->hid;
	__u8 *buf;
	__u8 *buf;
	int ret = 0;
	int ret = 0;


	if (!dev->hid_output_raw_report)
	mutex_lock(&minors_lock);
		return -ENODEV;
	dev = hidraw_table[minor]->hid;

	if (!dev->hid_output_raw_report) {
		ret = -ENODEV;
		goto out;
	}


	if (count > HID_MAX_BUFFER_SIZE) {
	if (count > HID_MAX_BUFFER_SIZE) {
		printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
		printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
				task_pid_nr(current));
				task_pid_nr(current));
		return -EINVAL;
		ret = -EINVAL;
		goto out;
	}
	}


	if (count < 2) {
	if (count < 2) {
		printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
		printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
				task_pid_nr(current));
				task_pid_nr(current));
		return -EINVAL;
		ret = -EINVAL;
		goto out;
	}
	}


	buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
	buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
	if (!buf)
	if (!buf) {
		return -ENOMEM;
		ret = -ENOMEM;
		goto out;
	}


	if (copy_from_user(buf, buffer, count)) {
	if (copy_from_user(buf, buffer, count)) {
		ret = -EFAULT;
		ret = -EFAULT;
		goto out;
		goto out_free;
	}
	}


	ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
	ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
out:
out_free:
	kfree(buf);
	kfree(buf);
out:
	mutex_unlock(&minors_lock);
	return ret;
	return ret;
}
}


@@ -164,7 +174,6 @@ static int hidraw_open(struct inode *inode, struct file *file)
		goto out;
		goto out;
	}
	}


	lock_kernel();
	mutex_lock(&minors_lock);
	mutex_lock(&minors_lock);
	if (!hidraw_table[minor]) {
	if (!hidraw_table[minor]) {
		printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
		printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
@@ -196,7 +205,6 @@ static int hidraw_open(struct inode *inode, struct file *file)


out_unlock:
out_unlock:
	mutex_unlock(&minors_lock);
	mutex_unlock(&minors_lock);
	unlock_kernel();
out:
out:
	return err;
	return err;


@@ -237,11 +245,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
	struct inode *inode = file->f_path.dentry->d_inode;
	struct inode *inode = file->f_path.dentry->d_inode;
	unsigned int minor = iminor(inode);
	unsigned int minor = iminor(inode);
	long ret = 0;
	long ret = 0;
	/* FIXME: What stops hidraw_table going NULL */
	struct hidraw *dev;
	struct hidraw *dev = hidraw_table[minor];
	void __user *user_arg = (void __user*) arg;
	void __user *user_arg = (void __user*) arg;


	lock_kernel();
	mutex_lock(&minors_lock);
	dev = hidraw_table[minor];

	switch (cmd) {
	switch (cmd) {
		case HIDIOCGRDESCSIZE:
		case HIDIOCGRDESCSIZE:
			if (put_user(dev->hid->rsize, (int __user *)arg))
			if (put_user(dev->hid->rsize, (int __user *)arg))
@@ -314,7 +323,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,


		ret = -ENOTTY;
		ret = -ENOTTY;
	}
	}
	unlock_kernel();
	mutex_unlock(&minors_lock);
	return ret;
	return ret;
}
}