How do you allow non-root users to access I2C on the Raspberry Pi 2?

I've compiled this code for accessing an MPU6050 sensor via I2C, and it works perfectly, but only when I call it via sudo.

I tried adding the pi user to the spi and i2c groups, and adding udev rules as explained here and here, but even after rebooting, those had little effect. I can run /usr/sbin/i2cdetect as a non-root user, but the C code I2Cdev::initialize() still crashes if run without sudo.

This is documented in the underlying bcm2835 library:

If the library runs with any other effective UID (ie not root), then bcm2835_init() will attempt to open /dev/gpiomem, and, if successful, will only permit GPIO operations. In particular, bcm2835_spi_begin() and bcm2835_i2c_begin() will return false and all other non-gpio operations may fail silently or crash.

Is there any workaround for this? Even if I add the pi user to the root group, it still silently crashes.

  • You seriously want people to follow 4 links? Have you tried setting suid on the compiled program? – Milliways Jul 18 '16 at 0:42
  • 2
    In case you aren't familiar with the concept of "suid" ... we can change the permissions on a binary file such that when it runs, it will run as the effective userid of the user that owns the file. For example, if you have a program that needs to run as root but you don't want to give all your users full root access, you change the owner of the file to be root and then execute chmod u+s on the file. This means that when a "regular" user runs the program, the program will run "as root". – Kolban Jul 18 '16 at 2:12

I think the bcm2835 C library is unique in being the only one which drives the I2C peripheral directly rather than using the Linux I2C driver.

This access was needed when the Pi first came out as there was no Linux I2C driver but nowadays it's a bit of an anachronism.

There is nothing stopping you using the standard driver from within the bcm2835 library - it's just standard device calls to /dev/i2c-0 and/or /dev/i2c-1. Using the standard calls might mean you can use bcm2835 without root privileges as long as the user is added to the i2c group.

I believe it only works when using sudo because you are accessing the bcm2835 directly and this requires elevated privileges.

If you use the linux i2c driver (sudo apt-get install i2c-tools will get you everything you need) then you can use device calls (which do not require elevated privileges). The code looks something like this:

    char *deviceName = (char*)"/dev/i2c-1";
    unsigned char bytesToSend[6] = {0,1,2,3,4,5};
    int bytes = 6;
    int i2cAddress = 0x3C;

    if ((i2cHandle = open(deviceName, O_RDWR)) < 0)
    {
        printf("error opening I2C\n");
    }
    else
    {
        if (ioctl(i2cHandle, I2C_SLAVE, i2cAddress) < 0)
        {
            printf("Error at ioctl\n");
        }
        else
        {
            write(i2cHandle, data, bytes);
        }

        // Close the i2c device bus
        close(*deviceName);
    }

As Kolban has mentioned, you can use the setuid bit; the example code there is about dropping the privileges at some point, so you do not have to actually add anything to use them, you just need to set the permissions on the compiled executable. You can do this as root or via sudo:

sudo chown root:root MPU6050_example_1
sudo chmod 4755 MPU6050_example_1

Note this won't work with a python or other script, but it will work with a compiled C++ program.

This is a theoretical security risk, although in this context not any more so than running the code sudo.

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.