From patchwork Tue Jan 3 22:58:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 9495807 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 71F1860405 for ; Tue, 3 Jan 2017 22:58:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 65A5F1FF35 for ; Tue, 3 Jan 2017 22:58:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 59DCF2793A; Tue, 3 Jan 2017 22:58:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 2AF231FF35 for ; Tue, 3 Jan 2017 22:58:48 +0000 (UTC) Received: (qmail 30322 invoked by uid 550); 3 Jan 2017 22:58:46 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: kernel-hardening@lists.openwall.com Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 30293 invoked from network); 3 Jan 2017 22:58:44 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition; bh=CuUYdYDKwy9lrhn6T14NCXxrLvgQu3NS2vTjIWyFHf0=; b=ZkUzEbYRhW4C1rTCdO0suGYNEpbeZpsPWNwmyY4bcyUHQ5gxzT7Z8hNG5G8M29dUUb UzFdsnDQIWPqdCKxX6Dqy6QWiSbHvDDl99HRAQHAm1lMiCA/xmT3ImyKh1EpadSYm36H T+4gkSsTtjtRs9V7GVVA4mogU0vjDkpXHFJbQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition; bh=CuUYdYDKwy9lrhn6T14NCXxrLvgQu3NS2vTjIWyFHf0=; b=uhlmajggl0S3bpa8p/ytE/Ja0hWzcxccMrvtq7rGJOWAfHxnJ883HqB7tJGolE7Hix Dgvvu59ohq7BA9hPzVMOgWxtUa+E0RhzR9yxpa1HA6PrZkKkEXOAbe7pS7kh57a+R0Lv QR7lHkra+M1MxnUou/oFt3TMQeWYWS/wjgmvXqtuEZzxcQwayAnflwmRJd12wmjjjJXD +9tn/gw2Fv2zwRRqoX/bBT1w6IDT2LdJdei6S2grKIRhADJoVUxvqSQY0APXEhmudPyn Vhr81Bry5GsCtjmER/HjJazs4D7xEgHHrTj1CVSM/fsNMU1z/QG8XibEC1AyzJs9BAQt +h5A== X-Gm-Message-State: AIkVDXLBfivV0UHXUEQaxh8XqE22EfH1r1z79LUq8dwTyzO7YHW2ccCaKwXZiljUaLylXbZg X-Received: by 10.99.63.74 with SMTP id m71mr116081967pga.16.1483484312789; Tue, 03 Jan 2017 14:58:32 -0800 (PST) Date: Tue, 3 Jan 2017 14:58:31 -0800 From: Kees Cook To: Greg Kroah-Hartman Cc: linux-kernel@vger.kernel.org, "Rafael J. Wysocki" , Len Brown , Pavel Machek , Matthew Garrett , Ulf Hansson , Mauro Carvalho Chehab , Tomeu Vizoso , Lukas Wunner , Madalin Bucur , Sudip Mukherjee , Rasmus Villemoes , Arnd Bergmann , Andrew Morton , Russell King , Petr Tesarik , linux-pm@vger.kernel.org, kernel-hardening@lists.openwall.com Message-ID: <20170103225831.GA113525@beast> MIME-Version: 1.0 Content-Disposition: inline Subject: [kernel-hardening] [PATCH] Allow userspace control of runtime disabling/enabling of driver probing X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett Various attacks are made possible due to the large attack surface of kernel drivers and the easy availability of hotpluggable hardware that can be programmed to mimic arbitrary devices. This allows attackers to find a single vulnerable driver and then produce a device that can exploit it by plugging into a hotpluggable bus (such as PCI or USB). This violates user assumptions about unattended systems being secure as long as the screen is locked. The kernel already has support for deferring driver binding in order to avoid problems over suspend/resume. By exposing this to userspace we can disable probing when the screen is locked and simply reenable it on unlock. This is not a complete solution - since this still permits device creation and simply blocks driver binding, it won't stop userspace drivers from attaching to devices and it won't protect against any kernel vulnerabilities in the core bus code. However, it should be sufficient to block attacks like Poisontap (https://samy.pl/poisontap/). Signed-off-by: Matthew Garrett Signed-off-by: Kees Cook --- .../ABI/testing/sysfs-kernel-disable-device-probe | 10 ++++++++ drivers/base/base.h | 2 -- drivers/base/dd.c | 10 ++++++++ drivers/base/power/main.c | 16 ++++++++++--- include/linux/device.h | 4 ++++ kernel/ksysfs.c | 28 ++++++++++++++++++++++ 6 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-kernel-disable-device-probe diff --git a/Documentation/ABI/testing/sysfs-kernel-disable-device-probe b/Documentation/ABI/testing/sysfs-kernel-disable-device-probe new file mode 100644 index 000000000000..1ca6c2d11d8b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-disable-device-probe @@ -0,0 +1,10 @@ +What: /sys/kernel/disable_device_probe +Date: December 2016 +KernelVersion: 4.11 +Contact: Matthew Garrett +Description + Disables automatic driver probing of any newly added devices. + If "1", driver probing is disabled - any newly added devices + will not have a driver bound to them. If "0", newly added + devices will be probed, along with any devices connected while + "1" was set. diff --git a/drivers/base/base.h b/drivers/base/base.h index ada9dce34e6d..7bee2e4e38ce 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -134,8 +134,6 @@ extern void device_remove_groups(struct device *dev, extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); -extern void device_block_probing(void); -extern void device_unblock_probing(void); /* /sys/devices directory */ extern struct kset *devices_kset; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a8b258e5407b..4d70fa41132c 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -191,6 +191,16 @@ static void driver_deferred_probe_trigger(void) } /** + * device_probing_deferred() - Get the current state of device probing + * + * Returns whether or not device probing is currently deferred + */ +bool device_probing_deferred(void) +{ + return defer_all_probes; +} + +/** * device_block_probing() - Block/defere device's probes * * It will disable probing of devices and defer their probes instead. diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 249e0304597f..b566e7a6140c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -59,6 +59,8 @@ struct suspend_stats suspend_stats; static DEFINE_MUTEX(dpm_list_mtx); static pm_message_t pm_transition; +static bool probing_deferred; + static int async_error; static char *pm_verb(int event) @@ -1024,8 +1026,12 @@ void dpm_complete(pm_message_t state) list_splice(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); - /* Allow device probing and trigger re-probing of deferred devices */ - device_unblock_probing(); + /* + * Allow device probing and trigger re-probing of deferred devices + * unless userspace has explicitly disabled probing + */ + if (!probing_deferred) + device_unblock_probing(); trace_suspend_resume(TPS("dpm_complete"), state.event, false); } @@ -1714,8 +1720,12 @@ int dpm_prepare(pm_message_t state) * hibernation and system behavior will be unpredictable in this case. * So, let's prohibit device's probing here and defer their probes * instead. The normal behavior will be restored in dpm_complete(). + * Skip this if probing is already deferred, otherwise we'll override + * explicitly configured state. */ - device_block_probing(); + probing_deferred = device_probing_deferred(); + if (!probing_deferred) + device_block_probing(); mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_list)) { diff --git a/include/linux/device.h b/include/linux/device.h index 491b4c0ca633..e7ca593605f6 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -43,6 +43,10 @@ struct iommu_ops; struct iommu_group; struct iommu_fwspec; +extern bool device_probing_deferred(void); +extern void device_block_probing(void); +extern void device_unblock_probing(void); + struct bus_attribute { struct attribute attr; ssize_t (*show)(struct bus_type *bus, char *buf); diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index ee1bc1bb8feb..22276140b47c 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /* rcu_expedited and rcu_normal */ @@ -144,6 +145,32 @@ static ssize_t fscaps_show(struct kobject *kobj, } KERNEL_ATTR_RO(fscaps); +/* Disable/reenable device probing*/ +static ssize_t disable_device_probe_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", device_probing_deferred()); +} + +static ssize_t disable_device_probe_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + bool disable_probing; + + if (kstrtobool(buf, &disable_probing)) + return -EINVAL; + + if (disable_probing) + device_block_probing(); + else + device_unblock_probing(); + + return count; +} +KERNEL_ATTR_RW(disable_device_probe); + #ifndef CONFIG_TINY_RCU int rcu_expedited; static ssize_t rcu_expedited_show(struct kobject *kobj, @@ -225,6 +252,7 @@ static struct attribute * kernel_attrs[] = { &rcu_expedited_attr.attr, &rcu_normal_attr.attr, #endif + &disable_device_probe_attr.attr, NULL };