如果程序设置了 setuid 位,为什么 /proc/self 中的文件最终归根所有?
Why do files in /proc/self end up being owned by root if a program has its setuid bit set?
我有这个小程序:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <sys/prctl.h>
extern char **environ;
int main()
{
char * const arglist[] = { "/bin/ls", "-l", "/proc/self/maps", NULL };
uid_t uid, euid, suid;
gid_t gid, egid, sgid;
getresuid(&uid, &euid, &suid);
printf("Before: uid: %u, euid: %u, suid: %u\n", uid, euid, suid);
uid = euid;
setresuid(uid, euid, suid);
getresuid(&uid, &euid, &suid);
printf(" After: uid: %u, euid: %u, suid: %u\n", uid, euid, suid);
getresgid(&gid, &egid, &sgid);
printf("Before: gid: %u, egid: %u, sgid: %u\n", gid, egid, sgid);
gid = egid;
setresuid(gid, egid, sgid);
getresuid(&gid, &egid, &sgid);
printf(" After: gid: %u, egid: %u, sgid: %u\n", gid, egid, sgid);
printf("Get result == %d\n", prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
printf("Set result == %d\n", prctl(PR_SET_DUMPABLE, 1, 0, 0, 0));
printf("Get result == %d\n", prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
if (fork())
{
return 0;
}
execve(arglist[0], arglist, environ);
}
我将此程序编译成名为 small-test
的可执行文件并将其所有权更改为测试用户:
[omnifarious@foohost ~]$ ls -l small-test
-rwxrwxr-x. 1 testing testing 8512 Oct 23 12:55 small-test
然后我运行程序:
[omnifarious@foohost ~]$ ./small-test
Before: uid: 1001, euid: 1001, suid: 1001
After: uid: 1001, euid: 1001, suid: 1001
Before: gid: 1001, egid: 1001, sgid: 1001
After: gid: 1001, egid: 1001, sgid: 1001
Get result == 1
Set result == 0
Get result == 1
-r--r--r--. 1 hopper hopper 0 Oct 23 14:50 /proc/self/maps
到目前为止,还不错。然后我这样做:
[omnifarious@foohost ~]$ sudo chmod ug+s ./small-test
[omnifarious@foohost ~]$ ls -l ./small-test
-rwsrwsr-x. 1 testing testing 8512 Oct 23 12:55 ./small-test
[omnifarious@foohost ~]$ ./small-test
Before: uid: 1001, euid: 1002, suid: 1002
After: uid: 1002, euid: 1002, suid: 1002
Before: gid: 1001, egid: 1002, sgid: 1002
After: gid: 1002, egid: 1002, sgid: 1002
Get result == 0
Set result == 0
Get result == 1
-r--r--r--. 1 root root 0 Oct 23 12:59 /proc/self/maps
为什么 /proc/self/maps
最终归 root
而不是 testing
或 omnifarious
所有?请注意,如果我删除 fork
.
结果不会改变
这让我烦恼的原因是我需要创建一个程序,将自己作为一个用户而不是执行它的用户放在命名空间中。这样我就无法访问启动该程序的用户拥有的 cgroup 和其他东西。但是不允许我写入程序的 uid_map
或 gid_map
,因此我无法正确设置命名空间。
注意: 我编辑了这个问题以包含对 prctl
的调用以设置(并读取)DUMPABLE
标志作为答案(以及manual) 表示重置它应该修复 /proc/self/*
文件的所有者。它没有,正如您在新程序中看到的那样。
编辑: 上面的程序有一个错误,它调用 setresuid
而不是 setresgid
。即使在添加对 prctl
的调用之后,这也是导致我出现问题的原因。如果进程的真实有效组和用户 ID 不同,则 prctl(PR_SET_DUMPABLE, 1);
调用无效。
出于安全原因,任何 suid 进程都默认将其 /proc/self
目录归 root 所有(以防止用户引发核心转储并检查其内存以获取有价值的信息)。
您可以在 suid
之后设置所有者,方法是使用 prctl PR_SET_DUMPABLE
手动使进程可转储。
这里是 proc(5)
,其中包含对正在发生的事情以及如何影响它的描述:
/proc/[pid]
There is a numerical subdirectory for each running
process; the subdirectory is named by the process
ID.
Each /proc/[pid] subdirectory contains the pseudo-
files and directories described below. These
files are normally owned by the effective user and
effective group ID of the process. However, as a
security measure, the ownership is made root:root
if the process's "dumpable" attribute is set to a
value other than 1. This attribute may change for
the following reasons:
* The attribute was explicitly set via the
prctl(2) PR_SET_DUMPABLE operation.
* The attribute was reset to the value in the
file /proc/sys/fs/suid_dumpable (described
below), for the reasons described in prctl(2).
Resetting the "dumpable" attribute to 1 reverts
the ownership of the /proc/[pid]/* files to the
process's real UID and real GID.
下面,suid_dumpable
说明了为什么默认是这样:
1 ("debug")
All processes dump core when possible.
(Reasons why a process might nevertheless
not dump core are described in core(5).)
The core dump is owned by the filesystem
user ID of the dumping process and no secu‐
rity is applied. This is intended for sys‐
tem debugging situations only: this mode is
insecure because it allows unprivileged
users to examine the memory contents of
privileged processes.
作为奖励,prctl(2)
列出了影响可倾倒性的非 suid 情况:
PR_SET_DUMPABLE (since Linux 2.3.20)
(...)
Normally, this flag is set to 1. However, it is
reset to the current value contained in the file
/proc/sys/fs/suid_dumpable (which by default has
the value 0), in the following circumstances:
* The process's effective user or group ID is
changed.
* The process's filesystem user or group ID is
changed (see credentials(7)).
* The process executes (execve(2)) a set-user-ID
or set-group-ID program, resulting in a change
of either the effective user ID or the effec‐
tive group ID.
(...)
我有这个小程序:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <sys/prctl.h>
extern char **environ;
int main()
{
char * const arglist[] = { "/bin/ls", "-l", "/proc/self/maps", NULL };
uid_t uid, euid, suid;
gid_t gid, egid, sgid;
getresuid(&uid, &euid, &suid);
printf("Before: uid: %u, euid: %u, suid: %u\n", uid, euid, suid);
uid = euid;
setresuid(uid, euid, suid);
getresuid(&uid, &euid, &suid);
printf(" After: uid: %u, euid: %u, suid: %u\n", uid, euid, suid);
getresgid(&gid, &egid, &sgid);
printf("Before: gid: %u, egid: %u, sgid: %u\n", gid, egid, sgid);
gid = egid;
setresuid(gid, egid, sgid);
getresuid(&gid, &egid, &sgid);
printf(" After: gid: %u, egid: %u, sgid: %u\n", gid, egid, sgid);
printf("Get result == %d\n", prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
printf("Set result == %d\n", prctl(PR_SET_DUMPABLE, 1, 0, 0, 0));
printf("Get result == %d\n", prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
if (fork())
{
return 0;
}
execve(arglist[0], arglist, environ);
}
我将此程序编译成名为 small-test
的可执行文件并将其所有权更改为测试用户:
[omnifarious@foohost ~]$ ls -l small-test
-rwxrwxr-x. 1 testing testing 8512 Oct 23 12:55 small-test
然后我运行程序:
[omnifarious@foohost ~]$ ./small-test
Before: uid: 1001, euid: 1001, suid: 1001
After: uid: 1001, euid: 1001, suid: 1001
Before: gid: 1001, egid: 1001, sgid: 1001
After: gid: 1001, egid: 1001, sgid: 1001
Get result == 1
Set result == 0
Get result == 1
-r--r--r--. 1 hopper hopper 0 Oct 23 14:50 /proc/self/maps
到目前为止,还不错。然后我这样做:
[omnifarious@foohost ~]$ sudo chmod ug+s ./small-test
[omnifarious@foohost ~]$ ls -l ./small-test
-rwsrwsr-x. 1 testing testing 8512 Oct 23 12:55 ./small-test
[omnifarious@foohost ~]$ ./small-test
Before: uid: 1001, euid: 1002, suid: 1002
After: uid: 1002, euid: 1002, suid: 1002
Before: gid: 1001, egid: 1002, sgid: 1002
After: gid: 1002, egid: 1002, sgid: 1002
Get result == 0
Set result == 0
Get result == 1
-r--r--r--. 1 root root 0 Oct 23 12:59 /proc/self/maps
为什么 /proc/self/maps
最终归 root
而不是 testing
或 omnifarious
所有?请注意,如果我删除 fork
.
这让我烦恼的原因是我需要创建一个程序,将自己作为一个用户而不是执行它的用户放在命名空间中。这样我就无法访问启动该程序的用户拥有的 cgroup 和其他东西。但是不允许我写入程序的 uid_map
或 gid_map
,因此我无法正确设置命名空间。
注意: 我编辑了这个问题以包含对 prctl
的调用以设置(并读取)DUMPABLE
标志作为答案(以及manual) 表示重置它应该修复 /proc/self/*
文件的所有者。它没有,正如您在新程序中看到的那样。
编辑: 上面的程序有一个错误,它调用 setresuid
而不是 setresgid
。即使在添加对 prctl
的调用之后,这也是导致我出现问题的原因。如果进程的真实有效组和用户 ID 不同,则 prctl(PR_SET_DUMPABLE, 1);
调用无效。
出于安全原因,任何 suid 进程都默认将其 /proc/self
目录归 root 所有(以防止用户引发核心转储并检查其内存以获取有价值的信息)。
您可以在 suid
之后设置所有者,方法是使用 prctl PR_SET_DUMPABLE
手动使进程可转储。
这里是 proc(5)
,其中包含对正在发生的事情以及如何影响它的描述:
/proc/[pid]
There is a numerical subdirectory for each running
process; the subdirectory is named by the process
ID.
Each /proc/[pid] subdirectory contains the pseudo-
files and directories described below. These
files are normally owned by the effective user and
effective group ID of the process. However, as a
security measure, the ownership is made root:root
if the process's "dumpable" attribute is set to a
value other than 1. This attribute may change for
the following reasons:
* The attribute was explicitly set via the
prctl(2) PR_SET_DUMPABLE operation.
* The attribute was reset to the value in the
file /proc/sys/fs/suid_dumpable (described
below), for the reasons described in prctl(2).
Resetting the "dumpable" attribute to 1 reverts
the ownership of the /proc/[pid]/* files to the
process's real UID and real GID.
下面,suid_dumpable
说明了为什么默认是这样:
1 ("debug")
All processes dump core when possible.
(Reasons why a process might nevertheless
not dump core are described in core(5).)
The core dump is owned by the filesystem
user ID of the dumping process and no secu‐
rity is applied. This is intended for sys‐
tem debugging situations only: this mode is
insecure because it allows unprivileged
users to examine the memory contents of
privileged processes.
作为奖励,prctl(2)
列出了影响可倾倒性的非 suid 情况:
PR_SET_DUMPABLE (since Linux 2.3.20)
(...)
Normally, this flag is set to 1. However, it is
reset to the current value contained in the file
/proc/sys/fs/suid_dumpable (which by default has
the value 0), in the following circumstances:
* The process's effective user or group ID is
changed.
* The process's filesystem user or group ID is
changed (see credentials(7)).
* The process executes (execve(2)) a set-user-ID
or set-group-ID program, resulting in a change
of either the effective user ID or the effec‐
tive group ID.
(...)