From patchwork Tue Apr 16 13:58:17 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kristian Hogsberg X-Patchwork-Id: 2449661 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 05EE63FD40 for ; Tue, 16 Apr 2013 13:58:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964879Ab3DPN6Z (ORCPT ); Tue, 16 Apr 2013 09:58:25 -0400 Received: from mail-ve0-f181.google.com ([209.85.128.181]:44738 "EHLO mail-ve0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964878Ab3DPN6Y (ORCPT ); Tue, 16 Apr 2013 09:58:24 -0400 Received: by mail-ve0-f181.google.com with SMTP id pa12so425542veb.26 for ; Tue, 16 Apr 2013 06:58:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :mime-version:content-type:content-transfer-encoding; bh=dYxo+h5Kd68MlTHWK0xTSHFn82Lsahh+2rCGlKMq9mg=; b=tQZFeueerBXXFLJZxfEe/vcbLIncZGX+zUFsnDxeR6qQPobjRfHUk3Z0+zKHolG8E1 69MnQncU1iU/ieCy3ge+6qdqB2T/UBnp3x98mu7k4znL7RIvVzb0qAA8ZGXbXdldWaHJ 2tYgM7n05TjSYvgBS91e/d1jpddhu3LkD8S0ApPMUyyCfAFshAk45g5aP+iz99QX8IqA I8RQT05G4ajh2EiYUx7ttVYpNGK+hUzm0gPbim2v3DwAxJIdGRnQA8Q1y1mSs5lc+6cO DNE9JpSbpQ/1I+C719YRem320uE9m988UOVCFi9i/wTxM+vsYk4vNFBCYZ4znjUQboWZ o8Jw== X-Received: by 10.58.181.201 with SMTP id dy9mr1597973vec.34.1366120703213; Tue, 16 Apr 2013 06:58:23 -0700 (PDT) Received: from localhost.localdomain (c-67-186-132-98.hsd1.ma.comcast.net. [67.186.132.98]) by mx.google.com with ESMTPS id tp10sm1494401vec.1.2013.04.16.06.58.21 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 16 Apr 2013 06:58:22 -0700 (PDT) From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= To: dmitry.torokhov@gmail.com, linux-input@vger.kernel.org Cc: robert@sixbynine.org, =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Subject: [PATCH RFC] input: Add evdev mute ioctl Date: Tue, 16 Apr 2013 09:58:17 -0400 Message-Id: <1366120697-25841-1-git-send-email-krh@bitplanet.net> X-Mailer: git-send-email 1.8.1.4 MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org This commit adds a new ioctl to the evdev device: EVIOCMUTE. The purpose of this ioctl it to temporarily block event delivery to a specific evdev client and prevent access to most of the ioctls. The use case is a setuid helper process for a display server, which opens input devices and passes the fds to the display server. On VT switch away from the server, it should stop reading events from its evdev input devices. However, if the display server runs as the user it can be ptraced or if the server loads user defined modules, the display server can no longer be trusted to not snoop on the evdev devices. The mute ioctl allows the setuid helper to mute evdev devices when switching away from the VT the server is running on. The idea is that the helper listens for the VT switching signals and when VT switch happens it notifies the display server, waits for the server to clean up and then the helper drops drm master (which also requires root), mutes evdev devices and the acks the VT switch. Why don't we just use revoke? The revoke syscall (when it's done) will work on filenames and shut down all fds open to the device. This will break all other processes that listen on evdev devices for legitimate reasons. It's the same reason we don't use the EVIOCGRAB ioctl for input devices. EVIOCMUTE lets the helper mute just the fd it gave to the display server without affecting anything else potentially using the device. Signed-off-by: Kristian Høgsberg --- drivers/input/evdev.c | 37 ++++++++++++++++++++++++++++++++++--- include/uapi/linux/input.h | 1 + 2 files changed, 35 insertions(+), 3 deletions(-) This idea comes from work on Wayland and Weston [1], but the setuid helper should work and is required for a non-root X server to function correctly as well (ie, do proper vt switching). Kristian diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index f0f8928..cea6c35 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; + int muted; unsigned int bufsize; struct input_event buffer[]; }; @@ -130,8 +131,9 @@ static void evdev_events(struct input_handle *handle, evdev_pass_values(client, vals, count, time_mono, time_real); else list_for_each_entry_rcu(client, &evdev->client_list, node) - evdev_pass_values(client, vals, count, - time_mono, time_real); + if (!client->muted) + evdev_pass_values(client, vals, count, + time_mono, time_real); rcu_read_unlock(); } @@ -674,6 +676,20 @@ static int evdev_handle_mt_request(struct input_dev *dev, return 0; } +static int evdev_mute(struct evdev *evdev, struct evdev_client *client) +{ + client->muted = 1; + + return 0; +} + +static int evdev_unmute(struct evdev *evdev, struct evdev_client *client) +{ + client->muted = 0; + + return 0; +} + static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) { @@ -687,12 +703,27 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, unsigned int size; int error; - /* First we check for fixed-length commands */ + /* Handle ioctls allowed in muted mode first */ switch (cmd) { + case EVIOCMUTE: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (p) + return evdev_mute(evdev, client); + else + return evdev_unmute(evdev, client); case EVIOCGVERSION: return put_user(EV_VERSION, ip); + default: + if (client->muted) + return -EACCES; + } + + /* Now check for fixed-length commands */ + switch (cmd) { case EVIOCGID: if (copy_to_user(p, &dev->id, sizeof(struct input_id))) return -EFAULT; diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 935119c..75eda72 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -154,6 +154,7 @@ struct input_keymap_entry { #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ +#define EVIOCMUTE _IOW('E', 0xb0, int) /* Mute event delivery */ /* * Device properties and quirks