kernel.deny_new_usb sysctl to deny new USB devices

linux-hardened exposes a kernel.deny_new_usb sysctl to deny new USB devices. This defaults to being disabled but we might want to enable this to block any USB-based attacks.

There’s multiple ways we can go about this.

  1. Enable it normally in /etc/sysctl.d.

  2. Patch it so the default is enabled (this would just change a single number, not a big change). This is better than (1) as it’d prevent attacks that happen before the sysctl is set.

  3. Tie it into the lockscreen so whenever the lockscreen is being used, new USB devices are denied. This would prevent anyone from inserting a malicious USB as soon as the user leaves their device. This is what GrapheneOS does and seems to be the most user-friendly approach. https://github.com/AndroidHardeningArchive/documentation/blob/master/technical_overview.md#attack-surface-reduction

2 Likes

Much easier to manage than the annoyaning restrictions we have

1 Like

Blockers before this can be worked at:

Things which can be done before this gets important:

Could you please describe what kind of attack you mean or give an example?

An USB device gets attached which then exploits a vulnerability in the kernel?

Quote Device handling security | Qubes OS

USB Security

The connection of an untrusted USB device to dom0 is a security risk since the device can attack an arbitrary USB driver (which are included in the linux kernel), exploit bugs during partition-table-parsing or simply pretend to be a keyboard. There are many ready-to-use implementations of such attacks, e.g. a USB Rubber Ducky. The whole USB stack is put to work to parse the data presented by the USB device in order to determine if it is a USB mass storage device, to read its configuration, etc. This happens even if the drive is then assigned and mounted in another qube.

To avoid this risk, use a USB qube.

Attaching a USB device to a VM (USB passthrough) will expose your target qube to most of the security issues associated with the USB-stack. If possible, use a method specific for particular device type (for example, block devices described above), instead of this generic one.

Or USB Rubber Ducky?

Which classes of attack is this supposed to prevent?

Implies that there is some kind of per VM filtering? How does that work?

It denies “new USB”. How are “old USB” configured? How would users allow an USB device?

No, not necessarily.
There is no such thing as “restrictions we have” related to USB. The only conscious change was thunar USB auto mounting disabling.

Otherwise “restrictions we have” is technically undefined. It’s not yet clear what causes these issues. Therefore “don’t do what we do now” and “do it as in this thread” isn’t possible because “don’t do what we do now” prerequisites knowledge of “what do we do now?”.

“don’t do what we do now” also mixes together security hardening changes which were applied for reason totally unrelated to USB such as proc-hidepid.

There is no way to skip the details of this forum thread Disk & USB Automount in Kicksecure - #23 by 59mpci2GJ5xlHhY and to generally say “doing as in this thread is better”.

I wouldn’t underestimate the difficulty of what is proposed in this forum thread either. I haven’t used this yet but looking at the documentation here (says “As of Jan 31, 2019, the information in this section has been deprecated. It may or may not be relevant for contemporary usage. Handle with care!”) does not look trivial either:

https://wiki.gentoo.org/wiki/Allow_only_known_usb_devices

2 Likes

Yes. USB adds a lot of local attack surface and are commonly used in attacks. See e.g. Stuxnet or BadUSB

Rubber duckies automatically exploit a vulnerability once plugged in. It’s not an “or”, it’s the same thing.

Qubes requires you to specifically passthrough USBs to a VM.

“old USB” means before the sysctl is set and “new USB” is after the sysctl is set.

They can temporarily disable deny_new_usb and re-enable it after plugging their USB in.

1 Like

Question is if malicious USBs can exploit the underlying USB PCI bus without ever being acknowledged/seen/loaded by the kernel.

2 Likes

If you’re asking whether they can exploit the underlying hardware/firmware, then the answer is probably yes but that’s out of our reach and the only mitigation at that point is ripping out your USB ports.

I also find it really unlikely they’d even attempt to exploit that when the kernel USB stack is a far more promising target as it has plenty of vulnerabilities found regularly (syzbot found over 80 vulns soon after it started fuzzing the USB stack and that was just the start).

If you’re asking whether they can still exploit the kernel, then no. The kernel attack surface is only really exposed once the USB is recognized by the kernel.

2 Likes

What about those users who only have keyboards / mice which are internally connected by USB? At first boot they would be presented with a broken system?

Could a sysctl still undo this? I.e. we could boot with this kernel boot parameter and then users could switch the sysctl to allow new USB devices?

1 Like

All devices connected at boot should be allowed. Any connected after boot should be denied.

Yes.

2 Likes

Looks really good overall.

Though a bit far in future (after ⚓ T961 fix USB auto mounting bug / document and ⚓ T960 hardened kernel Debian packaging and APT integration - hkapt).

Not sure that would be a trivial patch. I like the initiative of deny_new_usb but does not seem to have a complex state new vs old USB. (I am not suggesting it should.)

kernel/sysctl.c:int deny_new_usb __read_mostly = 0;
kernel/sysctl.c:EXPORT_SYMBOL(deny_new_usb);
kernel/sysctl.c:                .procname       = "deny_new_usb",
kernel/sysctl.c:                .data           = &deny_new_usb,
drivers/usb/core/hub.c:extern int deny_new_usb;
drivers/usb/core/hub.c: if (deny_new_usb) {

It is only used in function hub_port_connect which, correct me if I am wrong, is probably parsed at every boot for every port. By booting with deny_new_usb we would effectively block all USB.

Also when reading about deny_new_usb suggests that init scripts (systemd) should set this.


Proposal:

  • deny_new_usb after boot completed
  • set deny_new_usb when lockscreen
  • This could use a systray to indicate status and to easily toggle (left click) new USB disable/enable.
  • Enable action should have a timeout and notification how long until auto disable and timeout.

There is a systray for i3 here:

https://blog.lizzie.io/preventing-usb-attacks-with-linux-hardened.html

But we’d need a systray for XFCE.

Example XFCE systray (although that does not have clickable actions).

Related:

Patches welcome.

2 Likes

hub_port_connect is only called by hub_port_connect_change which is only called if something changes. In port_event:

if (connect_change)
                hub_port_connect_change(hub, port1, portstatus, portchange);

i.e. if a new device is removed/added which wasn’t there to begin with (I think). Although I’m not entirely sure on this. We’d need to test.

1 Like