How to Safely Write Raw Images to USB Sticks in Linux

dddeviceslinuxpermissionsusb

Trying lots of different Linux distributions on all kinds of hardware, I find myself typing commands like this quite often:

sudo dd if=xubuntu-13.10-desktop-amd64.iso of=/dev/sdc bs=10240

Needless to say, sooner or later I will mistype the destination and wipe a harddrive instead of the intended USB drive. I would like not to use sudo every time here.

On my system, a fairly modern Ubuntu, permissions on /dev/sdc are like: (when a stick is present):

$ ls -al /dev/sdc*
brw-rw---- 1 root disk 8, 32 Apr  6 22:10 /dev/sdc

How do I grant my regular user write access to random USB sticks but not other disks present in my system?

Best Answer

I think you can use UDEV to do what you want. Creating a rules file such as/etc/udev/rules.d/99-thumbdrives.rules you'd simply add a rule that will allow either a Unix group or user access to arbitrary USB thumb drives.

KERNEL=="sd*", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", OWNER="<user>", GROUP="<group>", MODE="0660"

Would create the device using the user <user> and group <group>.

Example

  1. After adding this line to my system.

    KERNEL=="sd*", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", OWNER="saml", GROUP="saml", MODE="0660"
    
  2. And reloading my rules:

    $ sudo udevadm control --reload-rules
    
  3. If I now insert a thumbdrive into my system, my /var/log/messages shows up as follows:

    $ sudo tail -f /var/log/messages
    Apr 13 11:48:45 greeneggs udisksd[2249]: Mounted /dev/sdb1 at /run/media/saml/HOLA on behalf of uid 1000
    Apr 13 11:51:18 greeneggs udisksd[2249]: Cleaning up mount point /run/media/saml/HOLA (device 8:17 is not mounted)
    Apr 13 11:51:18 greeneggs udisksd[2249]: Unmounted /dev/sdb1 on behalf of uid 1000
    Apr 13 11:51:18 greeneggs kernel: [171038.843969] sdb: detected capacity change from 32768000 to 0
    Apr 13 11:51:39 greeneggs kernel: [171058.964358] usb 2-1.2: USB disconnect, device number 15
    Apr 13 11:51:46 greeneggs kernel: [171066.053922] usb 2-1.2: new full-speed USB device number 16 using ehci-pci
    Apr 13 11:51:46 greeneggs kernel: [171066.134401] usb 2-1.2: New USB device found, idVendor=058f, idProduct=9380
    Apr 13 11:51:46 greeneggs kernel: [171066.134407] usb 2-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
    Apr 13 11:51:46 greeneggs kernel: [171066.134410] usb 2-1.2: Product: USBDrive
    Apr 13 11:51:46 greeneggs kernel: [171066.134412] usb 2-1.2: Manufacturer: JMTek
    Apr 13 11:51:46 greeneggs kernel: [171066.135470] usb-storage 2-1.2:1.0: USB Mass Storage device detected
    Apr 13 11:51:46 greeneggs kernel: [171066.136121] scsi17 : usb-storage 2-1.2:1.0
    Apr 13 11:51:46 greeneggs mtp-probe: checking bus 2, device 16: "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2"
    Apr 13 11:51:46 greeneggs mtp-probe: bus: 2, device: 16 was not an MTP device
    Apr 13 11:51:47 greeneggs kernel: [171067.139462] scsi 17:0:0:0: Direct-Access     JMTek    USBDrive         7.77 PQ: 0 ANSI: 2
    Apr 13 11:51:47 greeneggs kernel: [171067.140251] sd 17:0:0:0: Attached scsi generic sg2 type 0
    Apr 13 11:51:47 greeneggs kernel: [171067.142105] sd 17:0:0:0: [sdb] 64000 512-byte logical blocks: (32.7 MB/31.2 MiB)
    Apr 13 11:51:47 greeneggs kernel: [171067.144236] sd 17:0:0:0: [sdb] Write Protect is off
    Apr 13 11:51:47 greeneggs kernel: [171067.145988] sd 17:0:0:0: [sdb] No Caching mode page found
    Apr 13 11:51:47 greeneggs kernel: [171067.145998] sd 17:0:0:0: [sdb] Assuming drive cache: write through
    Apr 13 11:51:47 greeneggs kernel: [171067.153721] sd 17:0:0:0: [sdb] No Caching mode page found
    Apr 13 11:51:47 greeneggs kernel: [171067.153728] sd 17:0:0:0: [sdb] Assuming drive cache: write through
    Apr 13 11:51:47 greeneggs kernel: [171067.159028]  sdb: sdb1
    Apr 13 11:51:47 greeneggs kernel: [171067.164760] sd 17:0:0:0: [sdb] No Caching mode page found
    Apr 13 11:51:47 greeneggs kernel: [171067.164768] sd 17:0:0:0: [sdb] Assuming drive cache: write through
    Apr 13 11:51:47 greeneggs kernel: [171067.164775] sd 17:0:0:0: [sdb] Attached SCSI removable disk
    Apr 13 11:51:47 greeneggs kernel: [171067.635474] FAT-fs (sdb1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
    Apr 13 11:51:47 greeneggs udisksd[2249]: Mounted /dev/sdb1 at /run/media/saml/HOLA on behalf of uid 1000
    
  4. Now checking out the device files under /dev shows the following:

    $ ls -l /dev/sd*
    brw-rw----. 1 root disk 8,  0 Apr 13 09:17 /dev/sda
    brw-rw----. 1 root disk 8,  1 Apr 13 09:17 /dev/sda1
    brw-rw----. 1 root disk 8,  2 Apr 13 09:17 /dev/sda2
    brw-rw----. 1 saml saml 8, 16 Apr 13 11:51 /dev/sdb
    brw-rw----. 1 root disk 8, 17 Apr 13 11:51 /dev/sdb1
    

So it would seem to have worked.

Being more explicit

The above will work but will likely have these rules getting applied to every block device which isn't quite what we want. To narrow its focus a bit you can use ATTRS{..}==... attribute rules to restrict the application to specific hardware. In my case I only want it to be applied to a single USB thumbdrive.

Step #1 - uniquely id device

So to start we can use this command once we've mounted the particular thumb drive so that we can use udevadm to scrutinize it, groping it for its particular attributes.

Here I'm focusing on looking at the "manufacturer" and "product" attributes.

$ udevadm info -a -p $(udevadm info -q path -n /dev/sdb)|grep -iE "manufacturer|product"
    ATTRS{manufacturer}=="JMTek"
    ATTRS{idProduct}=="9380"
    ATTRS{product}=="USBDrive"
    ATTRS{idProduct}=="0020"
    ATTRS{manufacturer}=="Linux 3.13.7-100.fc19.x86_64 ehci_hcd"
    ATTRS{idProduct}=="0002"
    ATTRS{product}=="EHCI Host Controller"

NOTE: ATTRS{..}==.. attributes are attributes to parent devices in the hierarchy of where this device's device file is ultimately deriving from. So in our case the block device being added, /dev/sdb is coming from a USB parent device, so we're looking for this parent's attributes, ATTRS{manufacturer}=..., for example.

So in this example I'm selecting the manufacturer "JMTek" and the product "USBDrive".

Step #2 - modify .rules flie

So with these additional bits in hand let's add them to our original .rules file.

KERNEL=="sd*", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ATTRS{manufacturer}=="JMTek", ATTRS{product}=="USBDrive", OWNER="saml", GROUP="saml", MODE="0660"

Step #3 - Trying it out

Now when we reload our rules and unmount/remove/reinsert our USB thumbdrive again we get this rule:

$ ls -l /dev/sdb*
brw-rw----. 1 saml saml 8, 16 Apr 13 12:29 /dev/sdb
brw-rw----. 1 root disk 8, 17 Apr 13 12:29 /dev/sdb1

However if I insert a completely different device:

$ ls -l /dev/sdb*
brw-rw----. 1 root disk 8, 16 Apr 13 12:41 /dev/sdb
brw-rw----. 1 root disk 8, 17 Apr 13 12:41 /dev/sdb1

References

Related Question