浏览代码

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input update from Dmitry Torokhov:
 "The only change is David Hermann's new EVIOCREVOKE evdev ioctl that
  allows safely passing file descriptors to input devices to session
  processes and later being able to stop delivery of events through
  these fds so that inactive sessions will no longer receive user input
  that does not belong to them"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: evdev - add EVIOCREVOKE ioctl
Linus Torvalds 12 年之前
父节点
当前提交
8bf5e36d04
共有 2 个文件被更改,包括 32 次插入6 次删除
  1. 31 6
      drivers/input/evdev.c
  2. 1 0
      include/uapi/linux/input.h

+ 31 - 6
drivers/input/evdev.c

@@ -48,6 +48,7 @@ struct evdev_client {
 	struct evdev *evdev;
 	struct evdev *evdev;
 	struct list_head node;
 	struct list_head node;
 	int clkid;
 	int clkid;
+	bool revoked;
 	unsigned int bufsize;
 	unsigned int bufsize;
 	struct input_event buffer[];
 	struct input_event buffer[];
 };
 };
@@ -164,6 +165,9 @@ static void evdev_pass_values(struct evdev_client *client,
 	struct input_event event;
 	struct input_event event;
 	bool wakeup = false;
 	bool wakeup = false;
 
 
+	if (client->revoked)
+		return;
+
 	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
 	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
 				      mono : real);
 				      mono : real);
 
 
@@ -240,7 +244,7 @@ static int evdev_flush(struct file *file, fl_owner_t id)
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	if (!evdev->exist)
+	if (!evdev->exist || client->revoked)
 		retval = -ENODEV;
 		retval = -ENODEV;
 	else
 	else
 		retval = input_flush_device(&evdev->handle, file);
 		retval = input_flush_device(&evdev->handle, file);
@@ -429,7 +433,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	if (!evdev->exist) {
+	if (!evdev->exist || client->revoked) {
 		retval = -ENODEV;
 		retval = -ENODEV;
 		goto out;
 		goto out;
 	}
 	}
@@ -482,7 +486,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
 		return -EINVAL;
 		return -EINVAL;
 
 
 	for (;;) {
 	for (;;) {
-		if (!evdev->exist)
+		if (!evdev->exist || client->revoked)
 			return -ENODEV;
 			return -ENODEV;
 
 
 		if (client->packet_head == client->tail &&
 		if (client->packet_head == client->tail &&
@@ -511,7 +515,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
 		if (!(file->f_flags & O_NONBLOCK)) {
 		if (!(file->f_flags & O_NONBLOCK)) {
 			error = wait_event_interruptible(evdev->wait,
 			error = wait_event_interruptible(evdev->wait,
 					client->packet_head != client->tail ||
 					client->packet_head != client->tail ||
-					!evdev->exist);
+					!evdev->exist || client->revoked);
 			if (error)
 			if (error)
 				return error;
 				return error;
 		}
 		}
@@ -529,7 +533,11 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
 
 
 	poll_wait(file, &evdev->wait, wait);
 	poll_wait(file, &evdev->wait, wait);
 
 
-	mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+	if (evdev->exist && !client->revoked)
+		mask = POLLOUT | POLLWRNORM;
+	else
+		mask = POLLHUP | POLLERR;
+
 	if (client->packet_head != client->tail)
 	if (client->packet_head != client->tail)
 		mask |= POLLIN | POLLRDNORM;
 		mask |= POLLIN | POLLRDNORM;
 
 
@@ -795,6 +803,17 @@ static int evdev_handle_mt_request(struct input_dev *dev,
 	return 0;
 	return 0;
 }
 }
 
 
+static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
+			struct file *file)
+{
+	client->revoked = true;
+	evdev_ungrab(evdev, client);
+	input_flush_device(&evdev->handle, file);
+	wake_up_interruptible(&evdev->wait);
+
+	return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 			   void __user *p, int compat_mode)
 			   void __user *p, int compat_mode)
 {
 {
@@ -857,6 +876,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 		else
 		else
 			return evdev_ungrab(evdev, client);
 			return evdev_ungrab(evdev, client);
 
 
+	case EVIOCREVOKE:
+		if (p)
+			return -EINVAL;
+		else
+			return evdev_revoke(evdev, client, file);
+
 	case EVIOCSCLOCKID:
 	case EVIOCSCLOCKID:
 		if (copy_from_user(&i, p, sizeof(unsigned int)))
 		if (copy_from_user(&i, p, sizeof(unsigned int)))
 			return -EFAULT;
 			return -EFAULT;
@@ -1002,7 +1027,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	if (!evdev->exist) {
+	if (!evdev->exist || client->revoked) {
 		retval = -ENODEV;
 		retval = -ENODEV;
 		goto out;
 		goto out;
 	}
 	}

+ 1 - 0
include/uapi/linux/input.h

@@ -152,6 +152,7 @@ struct input_keymap_entry {
 #define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
 #define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
 
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
+#define EVIOCREVOKE		_IOW('E', 0x91, int)			/* Revoke device access */
 
 
 #define EVIOCSCLOCKID		_IOW('E', 0xa0, int)			/* Set clockid to be used for timestamps */
 #define EVIOCSCLOCKID		_IOW('E', 0xa0, int)			/* Set clockid to be used for timestamps */