As a rule, we must never use the root user in Linux to do tasks that are not inherently administrative. This sounds great, but sometimes, it doesn’t seem very easy. In this tutorial, we’ll discuss how to configure non-root serial port access.
2. Risks of Using Root Account
The fact is that when impersonating the root account, we have almost no permission constraints. This leads us to believe that it is alright to use root accounts regularly. However, by doing so, we expose our systems to a higher downtime risk. It can take just a single wrong command to bring a host down or even destroy its most important asset: data. That is exactly why, whenever we see a situation that seems to require root access to do anything unrelated to any administration task, we’re probably doing it the wrong way. One of these situations is using serial ports. A myriad of applications uses serial ports, from controlling external equipment to getting access to special-purpose or cellular data networks. Even some Bluetooth-connected devices expose access by the use of virtual serial ports. Needless to say, to safely use those serial ports, we must ensure that their application uses non-root users so that vulnerabilities on them shall not compromise the entire system.
3. Device Files Ownership and Permissions
Linux and all Unix-like systems use POSIX permissions for file systems. All device accesses, including serial ports, happen through device files in the /dev folder. Any file or directory on the file system has an owner user and a group association. Also, it has there flags that determine the access permissions to the owner, the group, and other users:
- r: right to read content
- w: right to write (for files), right to add files (for folders)
- x: right to execute (for files), right to dive into (for folders)
- s or t: setuid/setgid or sticky (also executable)
- S or T: setuid/setgid or sticky (not executable)
The s/S/t/T flags have no meaning on device files. Let us see how to figure out ownership and permissions for device files:
$ ls -l /dev total 0 crw-r--r-- 1 root root 10, 235 Feb 19 22:27 autofs drwxr-xr-x 2 root root 460 Feb 19 22:27 block drwxr-xr-x 2 root root 80 Feb 19 22:27 bsg crw-rw---- 1 root disk 10, 234 Feb 19 22:27 btrfs-control drwxr-xr-x 3 root root 60 Feb 19 22:27 bus crw-rw---- 1 root video 250, 0 Feb 19 22:27 cec0 drwxr-xr-x 2 root root 3120 Feb 19 22:34 char crw--w---- 1 root tty 5, 1 Feb 19 22:34 console drwxr-xr-x 7 root root 140 Feb 19 22:26 disk drwxr-xr-x 3 root root 120 Feb 19 22:27 dri crw------- 1 root root 10, 127 Feb 19 22:27 ecryptfs crw-rw---- 1 root i2c 89, 0 Feb 19 22:27 i2c-0 crw--w---- 1 root tty 4, 9 Feb 19 22:27 tty1 crw--w---- 1 root tty 4, 64 Feb 19 22:35 ttyS0 crw-rw---- 1 root dialout 4, 65 Feb 19 22:27 ttyS1
On that listing, the first column is the file entry metadata and permissions:
- The first character is the filesystem entry type: c stands for character devices, like serial ports, b for block devices, like hard drives, l for links, and d for folders
- Then each following set of three characters is the access permission flags for the owner, the group, and all other users. Each permission set is shown in the following order: read flag, write flag, and execute flag (plain or with setuid/setgid/sticky access)
By default, the root is the device owner, with both read and write permissions. That is why it seems easier to just use root credentials to use any device, serial ports included. Needless to say that writing to the wrong device can be quite dangerous. For instance, writing to a device like /dev/sda (first Sata device) might lead directly to data corruption. That’s exactly why we don’t mess with devices while on root capacity unless necessary.
4. Non-root Serial Port Access
The best way of gaining access to a serial port is by adding a non-privileged user to its associated group. For instance, in the above example, to use the ttyS1 device (2nd serial port on the host), we must add the user to the dialout group. This group name is used by default in all major Linux distributions to assign serial port permissions:
# sudo usermod -a -G dialout <username>
However, if we’re unsure about what is the correct group to use, we can do the following command to give the appropriate group membership to the user:
# sudo usermod -a -G $(stat -c "%G" <device path>) <username>
The group permissions are applied to the user session during login, so the target user must log in again to gain the group’s access.
In this tutorial, we discussed how to give non-privileged users access to serial ports. This method works for many other device types since the major distributions already have default groups assigned for several device classes. By using this technique, we avoid most of the root access needs for everyday tasks, thus reducing the risk exposure.