tl;dr
Debugging microcontrollers or even full-fledged single-board computers over UART requires you to be in the
dialoutgroup. That group, however, seems like a Pandora’s box to me that can open a wide attack surface. So, here we’re going to useudevto whitelist specific vendors, devices, etc. instead of blanket access usingdialoutgroup.
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:
KERNELis set tottyACM*and not1-4as we see in the excerpt above. This is because we want to modifyttyACM1and not its parent (usb1/1-4)- Similarly as above we also set the to
ttyand notusb manufacturerbelong to one ofttyACM1parents so we useATTRSinstead ofATTRto match parents’ attributes- Instead of
OWNER(don’t forget to replace it with your own username), we could also useGROUPto overridedialoutto 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:
