Encontrou a solução aqui .
O que você quer fazer é escrever um programa de habilitação de E / S confiável em C que permita acesso apenas às portas desejadas, e então use execvp () para executar seu script no espaço de endereço do chamador. Você irá então setuid root para o enabler de E / S compilado.
Veja um exemplo de código adaptado da fonte acima (não se esqueça de usar um bloco de endereço que você não se importa de escrever):
#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);
}
}
Vamos chamá-lo de io_enable.c, depois compilar e setuid root:
$ gcc io_enable.c -o io_enable
$ sudo chown root io_enable
$ sudo chmod u+s io_enable
Em seguida, podemos testá-lo com o seguinte script python:
#!/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()
Estou chamando de io_test.py e, em seguida, estou executando da seguinte forma:
$ ./io_enable python io_test.py
Parece que funciona:
$ 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.