Я управляю коробкой Gentoo Hardened, которая использует файловые возможности для устранения большей части необходимости в двоичных файлах setuid-root (например, /bin/ping
имеет CAP_NET_RAW и т. Д.).
Infact, единственный двоичный файл, который я оставил, является этим:
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 заботится о том, когда эта функция выходит из строя.
Проблема в том, что man-страница 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) Патч grantpt () в моем libc ничего не делает.
Я могу автоматизировать оба из них, но есть ли у кого-нибудь рекомендации по одному над другим или рекомендации, как еще решить эту проблему?
Как только это решится, я наконец смогу mount -o remount,nosuid /
.
источник
pty
(как следует), а на программу?Ответы:
Если ваш glibc достаточно актуален и devpts настроен правильно, не нужно вообще вызывать
pt_chown
помощника.Возможно, вы столкнулись с известной / потенциальной проблемой при удалении setuid-root
pt_chown
.grantpt()
поддерживаетсяdevfs
с Glibc-2.7 , были внесены изменения в Glibc-2.11 , хотя так , что вместо того , чтобы явно проверяяDEVFS_SUPER_MAGIC
, он проверяет , вместо того, чтобы увидеть , если это необходимо , чтобы сделать любую работу , прежде чем пытатьсяchown()
или падения обратно в призывеpt_chown
.От
glibc-2.17/sysdeps/unix/grantpt.c
Аналогичная строфа используется для проверки gid и разрешений. Проблема в том, что uid, gid и mode должны соответствовать ожиданиям (вы, tty и ровно 620; подтвердите с помощью
/usr/libexec/pt_chown --help
). Если нет, тоchown()
(что потребовало бы возможности CAP_CHOWN, CAP_FOWNER вызывающего двоичного файла / процесса) выполняется попытка, а если это не удается, выполняется попыткаpt_chown
внешнего помощника (который должен быть setuid-root). Для того,pt_chown
чтобы иметь возможность использовать возможности, он (и, следовательно, ваш glibc) должен быть скомпилированHAVE_LIBCAP
. Тем не менее , кажется , чтоpt_chown
это (как из Glibc-2,17 , и , как вы заметили , что Вы не высказали версию) жестко хотетьgeteuid()==0
независимо отHAVE_LIBCAP
, соответствующего кода изglibc-2.17/login/programs/pt_chown.c
:(Ожидание того, что
geteuid()==0
прежде чем пытаться использовать возможности, похоже, не совсем соответствует духу возможностей, я бы остановился на регистрации ошибки на этом.)Потенциальный обходной путь может заключаться в предоставлении CAP_CHOWN, CAP_FOWNER затронутым программам, но я действительно не рекомендую этого, поскольку вы, конечно, не можете ограничить это ptys.
Если это не поможет вам решить, заплаты
sshd
иscreen
чуть менее неприятен , чем латать Glibc. Поскольку проблема лежит в glibc, более чистый подход - выборочное использование DLL-инъекций для реализации фиктивной переменнойgrantpt()
.источник