我管理一个Gentoo Hardened框,该框使用文件功能来消除对setuid-root二进制文件(例如/bin/ping
具有CAP_NET_RAW等)的大多数需要。
实际上,我剩下的唯一二进制文件是:
abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ #
如果我删除setuid位或重新挂载我的根文件系统nosuid
,则sshd和GNU Screen停止工作,因为它们调用grantpt(3)
了它们的主伪终端,并且glibc显然执行了该程序来对下的伪伪终端进行chown和chmod /dev/pts/
,而GNU Screen会在何时关注此函数失败。
问题是,联机帮助页上grantpt(3)
明确指出,在Linux下,devpts
安装了文件系统后,不需要此类帮助程序二进制文件;内核会自动将从站的UID和GID设置为打开的进程的实际UID和GID /dev/ptmx
(通过调用getpt(3)
)。
我编写了一个小示例程序来演示这一点:
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int master;
char slave[16];
struct stat slavestat;
if ((master = getpt()) < 0) {
fprintf(stderr, "getpt: %m\n");
return 1;
}
printf("Opened a UNIX98 master terminal, fd = %d\n", master);
/* I am not going to call grantpt() because I am trying to
* demonstrate that it is not necessary with devpts mounted,
* the owners and mode will be set automatically by the kernel.
*/
if (unlockpt(master) < 0) {
fprintf(stderr, "unlockpt: %m\n");
return 2;
}
memset(slave, 0, sizeof(slave));
if (ptsname_r(master, slave, sizeof(slave)) < 0) {
fprintf(stderr, "ptsname: %m\n");
return 2;
}
printf("Device name of slave pseudoterminal: %s\n", slave);
if (stat(slave, &slavestat) < 0) {
fprintf(stderr, "stat: %m\n");
return 3;
}
printf("Information for device %s:\n", slave);
printf(" Owner UID: %d\n", slavestat.st_uid);
printf(" Owner GID: %d\n", slavestat.st_gid);
printf(" Octal mode: %04o\n", slavestat.st_mode & 00007777);
return 0;
}
在删除上述程序的setuid位的情况下观察它的运行:
aaron@abraxas ~ $ id
uid=1000(aaron) gid=100(users) groups=100(users)
aaron@abraxas ~ $ ./ptytest
Opened a UNIX98 master terminal, fd = 3
Device name of slave pseudoterminal: /dev/pts/17
Information for device /dev/pts/17:
Owner UID: 1000
Owner GID: 100
Octal mode: 0620
关于如何解决此问题,我只有几个想法:
1)将程序替换为仅返回0的框架。
2)在我的libc中修补grantpt()却什么也不做。
我可以同时实现这两个功能,但是有人对另一个提出了建议吗,还是有人建议如何解决这个问题?
解决这个问题后,我终于可以了mount -o remount,nosuid /
。
pty
(按理)检查程序?