Using ddccontrol as a non-root user

Most modern computer monitors support Display Data Channel which allows the screen brightness/contrast/input to be changed without using the on screen display. Many DDC implementations "just work" over HDMI, DisplayPort, or DVI by creating an i2c interface. Some monitors, like Dell Ultrasharps, also expose a DDC/i2c interface via USB.

Fortunately, several Linux programs exist to interact with the DDC interface. ddcutil is a CLI based program that expects monitors to use the MCCS 2.0 standard. ddccontrol provides a GUI as well as CLI interface. However, ddccontrol relies on a database of known working monitors. The GUI for ddccontrol may or may not work if the monitor is not 'officially' supported. Despite these shortcoming, ddccontrol was able to interface with one of my monitors while ddcutil was not able to.

Typically only the root user has access to the i2c devices (/dev/i2c-*) on a machine meaning gddccontrol and ddcutil have to be ran as root. One potential solution to allow non-root users to use DDC is to add them to the i2c group. However, this means users can access any i2c device, not just monitors supporting i2c, which has been expressed as a security concern.

My solution is to create a new group ddc that is explicitly granted access to DDC devices via udev rules. Non-root users can be added to the ddc group and will only gain write access to the necessary i2c devices for DDC to work.

The first step is to determine the i2c devices representing the DDC interfaces.

# ddccontrol -p
ddccontrol version 0.4.2  
Copyright 2004-2005 Oleg I. Vdovikin (oleg@cs.msu.su)  
Copyright 2004-2006 Nicolas Boichat (nicolas@boichat.ch)  
This program comes with ABSOLUTELY NO WARRANTY.  
You may redistribute copies of this program under the terms of the GNU General Public License.

Probing for available monitors...............  
Detected monitors :  
 - Device: dev:/dev/i2c-18
   DDC/CI supported: Yes
   Monitor Name: Dell U2518D
   Input type: Digital
  (Automatically selected)
 - Device: dev:/dev/i2c-10
   DDC/CI supported: Yes
   Monitor Name: LG IPS226V-PN
   Input type: Digital
...

ddccontrol found two monitors on /dev/i2c-18 and /dev/i2c-10. It can be useful to double check the devices are supported by udev with:

$ udevadm info -q path -n /dev/i2c-18
/devices/pci0000:00/0000:00:03.1/0000:0c:00.0/i2c-18/i2c-dev/i2c-18
$ udevadm info -q path -n /dev/i2c-10
/devices/pci0000:00/0000:00:03.1/0000:0c:00.0/i2c-10/i2c-dev/i2c-10

To write the necessary udev rules the KERNEL and SUBSYSTEM need to be known:

$ udevadm info -a -p $(udevadm info -q path -n /dev/i2c-18)

  looking at device '/devices/pci0000:00/0000:00:03.1/0000:0c:00.0/i2c-18/i2c-dev/i2c-18':
    KERNEL=="i2c-18"
    SUBSYSTEM=="i2c-dev"
    DRIVER==""
    ATTR{name}=="0000:0c:00.0"

  looking at parent device '/devices/pci0000:00/0000:00:03.1/0000:0c:00.0/i2c-18':
    KERNELS=="i2c-18"
    SUBSYSTEMS=="i2c"
    DRIVERS==""
    ATTRS{name}=="0000:0c:00.0"

With the KERNEL and SUBSYSTEM known, it is possible to write a udev rule changing the i2c device's owner to the ddc group.

# vim /etc/udev/rules.d/98-ddc.rules
KERNEL=="i2c-10", SUBSYSTEM=="i2c-dev", GROUP=="ddc", MODE="0660"  
KERNEL=="i2c-18", SUBSYSTEM=="i2c-dev", GROUP=="ddc", MODE="0660"  

For the udev rules to be applied, udev must be stopped, the rules reloaded, and then restarted. It may also be necessary to reload the i2c-dev kernel module:

# service udev stop
# udevadm control --reload-rules && udevadm trigger
# service udev start
# modprobe -r i2c-dev
# modprobe i2c-dev

Verifying the udev rule worked is straightforward:

$ ls -l /dev/ | grep i2c
...
crw-rw----  1 root ddc      89,  10 Jan 20 15:49 i2c-10  
...
crw-rw----  1 root ddc      89,  18 Jan 20 15:49 i2c-18  
...

All that is left is to add the non-root user to the ddc group:

# groupadd ddc
# usermod -a -G ddc userName
$ su - userName

Now the user can set the brightness without being root:

$ ddccontrol -r 0x10 -w 50 dev:/dev/i2c-18

Did this information improve the security of your box? Say thanks and help keep this site ad & analytics free by using my Amazon Affilliate URL. I'll receive a small commission on purchased made in the next 24 hours. Or, consider donating some ETH (0xf3c4a78c24D34E111f272Ac2AC72b1f01ba52DF3).