tl;dr
Debugging microcontrollers or even full-fledged single-board computers over UART requires you to be in the
dialout
group. That group, however, seems like a Pandora’s box to me that can open a wide attack surface. So, here we’re going to useudev
to whitelist specific vendors, devices, etc. instead of blanket access usingdialout
group.
Introduction
I started programming Raspi Pico a while ago using MicroPython and now plain C code.
As I’m a rookie, I needed some proper way to debug my code and UART sounded just right.
Pico uses tinyusb to simulate a tty over USB and it lists it under /dev/ttyACMx
with x
being a number, e.g., /dev/ttyACM1
.
These devices belong by default to user root
and group dialout
.
If you look elsewhere, you’d most probably find the recommendation to add your user to dialout
to be able to use these devices.
Me, on the other side, saw that as an attack surface that might get exposed if for some reason someone gains access to my user [1]: there might be other critical devies accessible through dialout
!
So I opted for udev
to control fine-grained access control to my devices.
Setting up udev
First you need to find out the some unique property about your device.
Find your device by running ll /dev/tty*
twice to see which new device has been added.
Say, that the device is under /dev/ttyACM1
, you can get udev info about it and its parents using:
udevadm info --attribute-walk /dev/ttyACM1
For Pico I get the following attributes (an excerpt only):
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4':
KERNELS=="1-4"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
...
ATTRS{idProduct}=="000a"
ATTRS{idVendor}=="2e8a"
ATTRS{manufacturer}=="Raspberry Pi"
ATTRS{serial}=="E66038B713108E30"
...
I can use any of idProduct
, idVendor
, manufacturer
, and serial
to setup a udev rule as follows:
KERNEL=="ttyACM[0-9]", SUBSYSTEM=="tty", ATTRS{manufacturer}=="Raspberry Pi", OWNER="$(whoami)"
There are a number of noteworthy items in file:
KERNEL
is set tottyACM*
and not1-4
as we see in the excerpt above. This is because we want to modifyttyACM1
and not its parent (usb1/1-4
)- Similarly as above we also set the to
tty
and notusb
manufacturer
belong to one ofttyACM1
parents so we useATTRS
instead ofATTR
to match parents’ attributes- Instead of
OWNER
(don’t forget to replace it with your own username), we could also useGROUP
to overridedialout
to another group.
finally, you can save that file under /lib/udev/rules.d/10-local.rules
and run udevadm control --reload
for changes to take effect. Plug out and in your usb cable and see that now you are the owner of the device!
[1] I asked on “Unix & Linux” StackExchange, if people are aware of any concrete security considerations when granting someone access to dialout
versus using udev
for fine-grained control.
Well, no one got back to me and my question got removed: