Re: [PATCH v4] Input: evdev - add EVIOCREVOKE ioctl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



David Herrmann <dh.herrmann@xxxxxxxxx> wrote:
>If we have multiple sessions on a system, we normally don't want
>background sessions to read input events. Otherwise, it could capture
>passwords and more entered by the user on the foreground session. This
>is
>a real world problem as the recent XMir development showed:
>  http://mjg59.dreamwidth.org/27327.html
>
>We currently rely on sessions to release input devices when being
>deactivated. This relies on trust across sessions. But that's not given
>on
>usual systems. We therefore need a way to control which processes have
>access to input devices.
>
>With VTs the kernel simply routed them through the active /dev/ttyX.
>This
>is not possible with evdev devices, though. Moreover, we want to avoid
>routing input-devices through some dispatcher-daemon in userspace
>(which
>would add some latency).
>
>This patch introduces EVIOCREVOKE. If called on an evdev fd, this
>revokes
>device-access irrecoverably for that *single* open-file. Hence, once
>you
>call EVIOCREVOKE on any dup()ed fd, all fds for that open-file will be
>rather useless now (but still valid compared to close()!). This allows
>us
>to pass fds directly to session-processes from a trusted source. The
>source keeps a dup()ed fd and revokes access once the session-process
>is
>no longer active.
>Compared to the EVIOCMUTE proposal, we can avoid the CAP_SYS_ADMIN
>restriction now as there is no way to revive the fd again. Hence, a
>user
>is free to call EVIOCREVOKE themself to kill the fd.
>
>Additionally, this ioctl allows multi-layer access-control (again
>compared
>to EVIOCMUTE which was limited to one layer via CAP_SYS_ADMIN). A
>middle
>layer can simply request a new open-file from the layer above and pass
>it
>to the layer below. Now each layer can call EVIOCREVOKE on the fds to
>revoke access for all layers below, at the expense of one fd per layer.
>
>There's already ongoing experimental user-space work which demonstrates
>how it can be used:
>http://lists.freedesktop.org/archives/systemd-devel/2013-August/012897.html
>
>Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxx>
>---
>Hi Dmitry
>
>Given the recent ABS_*-regression, I wrote a bunch of more aggressive
>stress-tests for this. I didn't found any regressions if EVIOCREVOKE is
>not
>used, but one with revoke on an empty queue in evdev_read(). Now fixed.
>Please
>let me know what your plans for this patch are (-next or -rc1?) so we
>can
>schedule accordingly.

I think this one is safer than extending axis numbers as there is no concerns about breaking stuff - it's brand new. So I think we can work it in -rc1.

> As a side note, will you attend LPC this year? We
>have a
>bunch of fancy stuff I'd like your opinion on (including
>device-properties, device-detection, ABS_* bit extension).

Yes. I'll get to new Orleans a couple days earlier (Sunday night) so if you are in town we could meet for drinks or such.

>
>Thanks and cheers
>David
>
> drivers/input/evdev.c      | 37 +++++++++++++++++++++++++++++++------
> include/uapi/linux/input.h |  1 +
> 2 files changed, 32 insertions(+), 6 deletions(-)
>
>diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
>index d2b34fb..b6ded17 100644
>--- a/drivers/input/evdev.c
>+++ b/drivers/input/evdev.c
>@@ -48,6 +48,7 @@ struct evdev_client {
> 	struct evdev *evdev;
> 	struct list_head node;
> 	int clkid;
>+	bool revoked;
> 	unsigned int bufsize;
> 	struct input_event buffer[];
> };
>@@ -164,6 +165,9 @@ static void evdev_pass_values(struct evdev_client
>*client,
> 	struct input_event event;
> 	bool wakeup = false;
> 
>+	if (client->revoked)
>+		return;
>+
> 	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
> 				      mono : real);
> 
>@@ -240,7 +244,7 @@ static int evdev_flush(struct file *file,
>fl_owner_t id)
> 	if (retval)
> 		return retval;
> 
>-	if (!evdev->exist)
>+	if (!evdev->exist || client->revoked)
> 		retval = -ENODEV;
> 	else
> 		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)
> 		return retval;
> 
>-	if (!evdev->exist) {
>+	if (!evdev->exist || client->revoked) {
> 		retval = -ENODEV;
> 		goto out;
> 	}
>@@ -482,7 +486,7 @@ static ssize_t evdev_read(struct file *file, char
>__user *buffer,
> 		return -EINVAL;
> 
> 	for (;;) {
>-		if (!evdev->exist)
>+		if (!evdev->exist || client->revoked)
> 			return -ENODEV;
> 
> 		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)) {
> 			error = wait_event_interruptible(evdev->wait,
> 					client->packet_head != client->tail ||
>-					!evdev->exist);
>+					!evdev->exist || client->revoked);
> 			if (error)
> 				return error;
> 		}
>@@ -529,7 +533,11 @@ static unsigned int evdev_poll(struct file *file,
>poll_table *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)
> 		mask |= POLLIN | POLLRDNORM;
> 
>@@ -795,6 +803,17 @@ static int evdev_handle_mt_request(struct
>input_dev *dev,
> 	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,
> 			   void __user *p, int compat_mode)
> {
>@@ -857,6 +876,12 @@ static long evdev_do_ioctl(struct file *file,
>unsigned int cmd,
> 		else
> 			return evdev_ungrab(evdev, client);
> 
>+	case EVIOCREVOKE:
>+		if (p)
>+			return -EINVAL;
>+		else
>+			return evdev_revoke(evdev, client, file);
>+
> 	case EVIOCSCLOCKID:
> 		if (copy_from_user(&i, p, sizeof(unsigned int)))
> 			return -EFAULT;
>@@ -1002,7 +1027,7 @@ static long evdev_ioctl_handler(struct file
>*file, unsigned int cmd,
> 	if (retval)
> 		return retval;
> 
>-	if (!evdev->exist) {
>+	if (!evdev->exist || client->revoked) {
> 		retval = -ENODEV;
> 		goto out;
> 	}
>diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
>index 2fb6fae..d61c61c 100644
>--- a/include/uapi/linux/input.h
>+++ b/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 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 */
> 

Hi David,
Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux