Run Python Portio script as normal user without root access

5,162

Solution 1

Found the solution here.

What you want to do is write a trusted I/O enabling program in C that allows access to only the desired ports, then uses execvp() to execute your script at the caller's address space. You'll then setuid root to the compiled I/O enabler.

Here's some sample code adapted from the above source (be sure to use an address block you don't mind writing to):

#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>

#define DESIRED_PORT    0x300
#define NUM_BYTES       8

int main(int argc, char*argv[])
{
    if (argc < 2) {
        printf("Error: no target program specified.\n");
        exit(1);
    }

    if (ioperm(DESIRED_PORT, NUM_BYTES, 1)) {
        printf("Error: couldn't set port permissions.\n");
        exit(1);
    }

    // Set uid to current user's id before executing the script
    setgid(getgid());
    setuid(getuid());

    if (execvp(argv[1], &argv[1]) < 0) {
        printf("Error: target program execution error.\n");
        exit(1);
    }
}

Let's call it io_enable.c, then compile and setuid root:

$ gcc io_enable.c -o io_enable
$ sudo chown root io_enable
$ sudo chmod u+s io_enable

Next, we can test it with the following python script:

#!/usr/bin/python
import portio

ADDR = 0x300

fd = open('/tmp/portio.log', 'w')

for i in range(10):
    portio.outb(i, ADDR)
    fd.write('Wrote %d, read %d.\n' % (i, portio.inb(ADDR)))

fd.close()

I'm calling it io_test.py and then running it like so:

$ ./io_enable python io_test.py

Looks like it works:

$ cat /tmp/portio.log
Wrote 0, read 0.
Wrote 1, read 1.
Wrote 2, read 2.
Wrote 3, read 3.
Wrote 4, read 4.
Wrote 5, read 5.
Wrote 6, read 6.
Wrote 7, read 7.
Wrote 8, read 8.
Wrote 9, read 9.

Solution 2

Add this line to the sudoers file (use the visudo program, never edit the sudoers file directly), where bob is the name of the user who must be allowed to run the script:

bob ALL = (root) NOPASSWD: /path/to/my/script

If you want this for multiple users, put them in a group resetters and make that sudoers line

%resetters ALL = (root) NOPASSWD: /path/to/my/script

If there are other rules involving bob, take care that the last match counts in the sudoers file. So put the rules with NOPASSWD: below the rules without it.

Share:
5,162

Related videos on Youtube

user5881
Author by

user5881

Updated on September 18, 2022

Comments

  • user5881
    user5881 over 1 year

    I know there are risks running a root script as a normal user, but in this case I don't have a choice and what I am doing is machine related. I have an Small Board Computer that has GPIO ports and I need to use one of the outputs to reset a device by toggling a shutdown line. That part works fine and the device resets as it should.

    My problem is that I wrote a python script to reset the device and it works, but I have to run it as root or "sudo program name, enter password". But I need this to work as a normal user without root permissions. In other words I added a normal user and I cannot run the script no matter what I do.

    I have tried adding the user to the sudoer file, but that did not work and was completely ignored. I have changed the permissions, set SUID bit and everything else I can think of, but still it asks for a root password. The only thing that did work was when I opened up Users and Groups and added the user to the Sudo group, but then the user had access to programs I would rather it did not as it was just like my default admin user. That is not what I want. I would like to somehow limit what that user has access to, to a single script or program.

    I have had other people suggest that I need to write a driver, but I don't really know how to do that or exactly what they mean and usually they do not want to elaborate. Though I have used Linux some I would not consider myself and expert especially in this area. Anyone have any ideas how to do this?

    • Admin
      Admin almost 13 years
      Have you tried creating a custom group and adding your user to that group. Then you can set the GID of your script to point to the new group you created and chmod 775 to allow it to execute. If not, could the password be from something you do INSIDE your code? (not exactly to do with running it)