Zarządzam modułem Gentoo Hardened, który korzysta z możliwości plików, aby wyeliminować większość potrzebnych plików binarnych z katalogu root setuid (np. /bin/ping
Ma CAP_NET_RAW itp.).
W rzeczywistości, jedyne pliki binarne, które mi pozostały, to:
abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ #
Jeśli usunę bit setuid lub ponownie zainstaluję mój główny system plików nosuid
, sshd i GNU Screen przestaną działać, ponieważ wywołują grantpt(3)
swoje pesudotermale nadrzędne i glibc najwyraźniej uruchamia ten program, aby zmienić i przeskoczyć pseudoterminal podrzędny /dev/pts/
, a GNU Screen dba o to, kiedy ta funkcja zawodzi.
Problem polega na tym, że strona podręcznika grantpt(3)
wyraźnie stwierdza, że pod Linuksem, z devpts
zamontowanym systemem plików, nie jest wymagany taki plik binarny pomocnika; jądro automatycznie ustawi UID i GID urządzenia podrzędnego na rzeczywisty UID i GID procesu, który został otwarty /dev/ptmx
(przez wywołanie getpt(3)
).
Napisałem mały przykładowy program, aby to zademonstrować:
#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;
}
Obserwuj to w akcji z usuniętym bitem setuid z wyżej wymienionego programu:
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
Mam tylko kilka pomysłów na obejście tego problemu:
1) Zamień program na szkielet, który po prostu zwraca 0.
2) Patch granpt () w moim libc, aby nic nie robić.
Mogę zautomatyzować oba z nich, ale czy ktoś ma rekomendacje dla jednego lub drugiego, czy też jak to rozwiązać?
Gdy problem zostanie rozwiązany, w końcu mogę mount -o remount,nosuid /
.
źródło
pty
(jak powinny), ale do programu?Odpowiedzi:
Jeśli twój glibc jest dość aktualny, a devpts jest skonfigurowane poprawnie, nie powinno być potrzeby wywoływania
pt_chown
pomocnika.Być może napotykasz znany / potencjalny problem podczas usuwania rootkera setuid
pt_chown
.grantpt()
obsługiwanydevfs
przez glibc-2.7 , zmiany zostały wprowadzone w glibc-2.11, ale zamiast jawnego sprawdzaniaDEVFS_SUPER_MAGIC
, zamiast tego sprawdza, czy musi wykonać jakąkolwiek pracę przed podjęciem próbychown()
powrotu do wywołaniapt_chown
.Z
glibc-2.17/sysdeps/unix/grantpt.c
Podobna zwrotka służy do sprawdzania gid i uprawnień. Chodzi o to, że identyfikator UID, GID i tryb muszą odpowiadać oczekiwaniom (ty, tty i dokładnie 620; potwierdź za pomocą
/usr/libexec/pt_chown --help
). Jeśli nie,chown()
(co wymagałoby możliwości CAP_CHOWN, CAP_FOWNER wywołującego pliku binarnego / procesu), podejmowana jest próba, a jeśli to się nie powiedzie, podejmowana jest próba użyciapt_chown
zewnętrznego pomocnika (który musi być rootem setuid). Abypt_chown
móc korzystać z możliwości, należy go skompilować (a więc i glibc)HAVE_LIBCAP
. Wydaje się jednak , żept_chown
jest (od wersji glibc-2.17 i jak zauważyłeś, choć nie podałeś wersji) na stałe zakodowany, aby chcieć,geteuid()==0
niezależnie odHAVE_LIBCAP
, odpowiedniego kodu zglibc-2.17/login/programs/pt_chown.c
:(Przy nadziei
geteuid()==0
przed próbą użycia możliwości nie wydaje się być w duchu możliwości, postanowiłbym zgłosić błąd w tym.)Potencjalnym obejściem może być przekazanie CAP_CHOWN, CAP_FOWNER zagrożonym programom, ale tak naprawdę nie polecam tego, ponieważ nie można tego oczywiście ograniczyć do ptys.
Jeśli to nie pomoże go rozwiązać, łatanie
sshd
iscreen
jest nieco mniej nieprzyjemne niż łatanie glibc. Ponieważ problem leży w glibc, czystszym podejściem byłoby selektywne użycie zastrzyku DLL do implementacji manekinagrantpt()
.źródło