Linux – How to simulate /proc/sys/kernel/grsecurity/deny_new_usb without grsecurity

grsecuritylinuxSecurityusb

How do I flexibly enable and disable plugging in new USB devices (running driver code responsible for those devices) at runtime without Grsecurity patch?

Are there other approaches or alternative kernel patches with this feature?


Reopen: Differences and comments about the proposed duplicate question How to safely insert USB stick/device to Linux computer?

  • Linked question asks about always selectively accepting some devices, this question asks about accepting all devices in selected moments of time (and denying anything in other moments).
  • Primary answer (USBGuard) is a userland solution. It seems to only prevent udev actions. It's unlikely prevent scanning a block device for partitions, creating network interface and querying its metadata or registering some /dev/input/eventX node. In-kernel attack surface seems to be exposed.
  • Another answer partially links to Grsecurity which is explicitly ruled out by this question's statement.

As far as I remember, there were plans to make screen-locked desktop Linux systems not accept any USB devices until screen is unlocked. This means there may be some patches about this somewhere.

Best Answer

Here is my patch for Linux kernel version 4.19.18:

From e5be5f1e696f5d41d992ac67d688c40045e81e95 Mon Sep 17 00:00:00 2001
From: Vitaly _Vi Shukela <vi0oss@gmail.com>
Date: Tue, 29 Jan 2019 21:01:08 +0300
Subject: [PATCH] Introduce dev.deny_new_usb sysctl flag

---
 drivers/usb/core/hub.c | 9 +++++++++
 kernel/sysctl.c        | 9 +++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index cc62707c0251..fb4483b80bac 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -46,6 +46,9 @@
  * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
 static DEFINE_SPINLOCK(device_state_lock);

+/* Skip handling of USB device plugging. Like /proc/sys/kernel/grsecurity/deny_new_usb. */
+int deny_new_usb __read_mostly = 0;
+
 /* workqueue to process hub events */
 static struct workqueue_struct *hub_wq;
 static void hub_event(struct work_struct *work);
@@ -4933,6 +4936,12 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
            goto done;
        return;
    }
+
+   if (deny_new_usb) {
+       printk(KERN_WARNING "Denying insertion of new USB device because of /proc/sys/dev/deny_new_usb is set to nonzero");
+       goto done;
+   }
+
    if (hub_is_superspeed(hub->hdev))
        unit_load = 150;
    else
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index f77df9f5fdb5..b0c14ad347c7 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -114,6 +114,8 @@ extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
 extern int sysctl_nr_trim_pages;
 #endif

+extern int deny_new_usb;
+
 /* Constants used for minimum and  maximum */
 #ifdef CONFIG_LOCKUP_DETECTOR
 static int sixty = 60;
@@ -1905,6 +1907,13 @@ static struct ctl_table debug_table[] = {
 };

 static struct ctl_table dev_table[] = {
+   {
+       .procname   = "deny_new_usb",
+       .data       = &deny_new_usb,
+       .maxlen     = sizeof(int),
+       .mode       = 0644,
+       .proc_handler   = &proc_dointvec,
+   },
    { }
 };

-- 
2.20.1

It is based on code from Grsecurity. It uses /proc/sys/dev/deny_new_usb instead of /proc/sys/kernel/grsecurity/deny_new_usb.

Related Question