以 root 身份打开文件,但在读取文件之前放弃权限?

Open a file as root, but drop privileges before reading from it?

TL;DR

我正在编写 C 程序。我需要拥有 fopen sysfs 文件的 root 权限,而且我仍然需要 root 权限才能从中读取。但是,由于我的程序需要持续读取 sysfs 文件,这意味着它需要一直提升权限。我想尽快放弃 root 权限。解决此问题的公认方法是什么?

详情

我正在编写一个与 sysfs 交互的程序。如果我 运行 在 shell 上执行命令,我会使用:

myuser@mymachine:~$ sudo su
root@mymachine:/home/myhomedir# cd /sys/class/gpio
root@mymachine:/sys/class/gpio# echo 971 > export
root@mymachine:/sys/class/gpio# cat gpio971/value
0
root@mymachine:/sys/class/gpio# exit

我需要在非特权用户可调用的 C 程序中 运行 这些命令。一种方法是使用 fopenfprintffscanf 等以通常的方式编写程序,并让用户 运行 通过 sudo 编写程序].但是,这意味着用户需要是 sudoer,程序将一直具有 root 权限。

另一个我非常喜欢的解决方案(因为不必将用户添加到 sudoers)是将程序的所有者更改为 root,并设置 setuid 位。 (这是我从 here 那里学到的)。

但是,有些事情我想知道。我想做的是在程序的 euid 为 0 时打开 sysfs 文件,然后立即放弃所有权限(为了安全)。然后,既然文件已经打开,我们只需 setuid() 到用户的 UID。但是,尽管我不能完全确定,但这是行不通的。这是我的代码的相关部分:

//At this point, due to the file permissions on the executable,
//euid = 0 and ruid = 1000. I know the following 4 lines work.
FILE *export = fopen("/sys/class/gpio/export", "wb");
fprintf(export, "971\n");
fclose(export);

FILE *sw_gpio = fopen("/sys/class/gpio971/value", "rb");

setuid(1000);
//Now euid = 1000 and ruid = 1000

int switch_val = -1;
fscanf(sw_gpio, "%d", &switch_val);
printf("Switch value: %d\n", switch_val); //-1
//Even though the only possible values in this sysfs file are 0 and 1,
//switch_val is still equal to -1

fclose(sw_gpio);

所以我似乎需要保持更高的权限才能从 /sys/class/gpio/gpio971/value 读取。但这正是我想要的!该程序将需要在整个程序执行过程中轮询该值,我不想一直使用 root 权限。

最后,为了完成,这里是我在我的可执行文件上设置的权限:

-rwsr-xr-x 1 root myuser 10943 Jan 1 20:17 main*

那么如何放弃 root 权限,但继续从访问受控的 sysfs 文件中读取?

我还没有用 /sysfs 尝试过这个,但即使是普通文件,我的理解是文件 streams 在调用 [= 后不会保留访问权限11=]。 File handles 可以,但是,出于我不明白的原因。所以,如果你的系统表现得像我的(x64 上的 Fedora 20),你可以使用 open()/read() 而不是 fopen()/fscanf()