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.
Best Answer
Sure: you can set the setuid bit. On a modern system, the simplest command is:
or, if the program is already known to have mode 755:
This assumes the program is owned by
root
. You'll need to change the file's owner, too, if it is currently owned by someone else.Do read that Wikipedia article, particularly the Security section. There's a reason only root can do this to a file, and why few executables on your system have this bit set already.