It is risky to issue a command like sudo dd if=image of=/dev/sdb bs=1M
due to the risk of typing sdb
to something else (e.g. internal drive). If an error has been made, the internal hard drive may get erased. This post proposes a solution by using udev rules, which will allow read/write access to USB drive without sudo
and no password required. These udev rules does not affect SATA-based storage devices.
The challenge
There’s been once that one of my colleagues have erased his internal drive by accident while using dd
by specifying the wrong device node. Every time we issue command such as sudo dd if=image.raw of=/dev/sdb bs=1M
, there is a risk involved, and being careful is not enough.
The following udev rules will change the group ownership of the device node of USB storage devices, enable the member of a specific group to read/write USB flash drive and card readers directly, with no need to issue command sudo
. It can
- Make our work easier by not asking for the password.
- The write attempt will fail if we specify the wrong device node.
- Initiating
sudo dd
will require a password by default.
The attempt will fail because these udev rules only apply to USB storage devices, not SATA-based block devices.
Edit /etc/udev/rules.d/99-usb-storage.rules
ACTION=="add",KERNEL=="sd*",SUBSYSTEM=="block",ENV{DEVTYPE}=="disk|partition",SUBSYSTEMS=="usb",DRIVERS=="usb-storage|uas",GOTO="usb_storage_label_1" GOTO="usb_storage_label_end" LABEL="usb_storage_label_1" KERNEL=="sd[a-z]", ENV{DEVTYPE}=="disk", GOTO="usb_storage_label_2" KERNEL=="sd[a-z][0-9]*",ENV{DEVTYPE}=="partition",ATTR{partition}=="*",GOTO="usb_storage_label_2" GOTO="usb_storage_label_end" LABEL="usb_storage_label_2" GROUP="sudo" GOTO="usb_storage_label_end" LABEL="usb_storage_label_end"
How it works
- The first two lines limit the udev rules only apply to USB storage device using driver
usb-storage
oruas
. - The section after label
usb_storage_label_1
further filter the type of device node (disk or partition) and the name of device node. (just because I’m paranoid) - Section
usb_storage_label_2
change the group of the device node to sudo. So the member of group sudo can have read/write access to these device nodes without issuing command sudo.
Assuming sdb
is a USB storage device, it will make the device node looks like
$ ll /dev/sd* brw-rw---- 1 root disk 8, 0 2018-07-23 17:50:00 /dev/sda brw-rw---- 1 root sudo 8, 16 2018-07-23 19:04:18 /dev/sdb brw-rw---- 1 root sudo 8, 17 2018-07-23 19:04:29 /dev/sdb1 brw-rw---- 1 root sudo 8, 18 2018-07-23 19:04:18 /dev/sdb2
A more advanced version
If you have USB flash drive which carries important data, you may add it to the black list to avoid accidental erasure. In this example, it avoid applying GROUP="sudo"
to
- USB disk which is formatted as encrypted volume (LUKS)
- USB partition (e.g., /dev/sdx1) which is formatted as encrypted volume. Be aware this does not protect the disk (/dev/sdx) from accidental erasure.
- A Kingston USB disk and partition 2 with the serial number specified. Partition 1 is not protected.
- A Seagate USB disk and partition with a specific serial number.
- Disk and partition device node of ThinkPad X280 microSD card reader.
Edit /etc/udev/rules.d/99-usb-storage.rules
ACTION=="add",KERNEL=="sd*",SUBSYSTEM=="block",ENV{DEVTYPE}=="disk|partition",SUBSYSTEMS=="usb",DRIVERS=="usb-storage|uas",GOTO="usb_storage_label_1" GOTO="usb_storage_label_end" LABEL="usb_storage_label_1" KERNEL=="sd[a-z]", ENV{DEVTYPE}=="disk", GOTO="usb_storage_label_2" KERNEL=="sd[a-z][0-9]*",ENV{DEVTYPE}=="partition",ATTR{partition}=="*",GOTO="usb_storage_label_2" GOTO="usb_storage_label_end" LABEL="usb_storage_label_2" # Blacklist LUKS disk and partitions ENV{ID_FS_TYPE}=="crypto_LUKS",GOTO="usb_storage_label_end" ENV{ID_FS_USAGE}=="crypto",GOTO="usb_storage_label_end" # Blacklist Kingston USB - disk and partition 2 ENV{ID_SERIAL}=="Kingston_DataTraveler_3.0_0123456789ABCDEF-0:0",ENV{DEVTYPE}=="disk",GOTO="usb_storage_label_end" ENV{ID_SERIAL}=="Kingston_DataTraveler_3.0_0123456789ABCDEF-0:0",ENV{DEVTYPE}=="partition",ENV{ID_PART_ENTRY_NUMBER}=="2",GOTO="usb_storage_label_end" # Blacklist Seagate 3.5 inch HDD ENV{ID_SERIAL}=="Seagate_Expansion_Desk_01234567-0:0",GOTO="usb_storage_label_end" # Blacklist ThinkPad X280 built-in SD card reader ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0",GOTO="usb_storage_label_end" GROUP="sudo" GOTO="usb_storage_label_end" LABEL="usb_storage_label_end"
There is a limitation on blacklist implementation as it’s hard to cover the disk (parent) of a LUKS partition. Not quite sure whether it’s possible to improve this.
Appendix
Tested on Ubuntu Desktop 18.04 (bionic)
To avoid automount in Ubuntu 18.04, install dconf-editor
and modify the following values
- org.gnome.desktop.media-handling.automount
- org.gnome.desktop.media-handling.automount-open