Administro un cuadro Gentoo Hardened que utiliza capacidades de archivo para eliminar la mayor parte de la necesidad de binarios setuid-root (por ejemplo, /bin/ping
tiene CAP_NET_RAW, etc.).
De hecho, el único binario que me queda es este:
abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ #
Si elimino el bit setuid, o vuelvo a montar mi sistema de archivos raíz nosuid
, sshd y GNU Screen dejan de funcionar, porque llaman grantpt(3)
a sus pesudoterminals maestros y glibc aparentemente ejecuta este programa para reconocer y cambiar el pseudoterminal esclavo /dev/pts/
, y GNU Screen se preocupa por cuándo esta función falla
El problema es que la página de manual para grantpt(3)
explícitamente establece que bajo Linux, con el devpts
sistema de archivos montado, no se requiere dicho binario auxiliar; el kernel configurará automáticamente el UID y GID del esclavo al UID y GID real del proceso que se abrió /dev/ptmx
(mediante una llamada getpt(3)
).
He escrito un pequeño programa de ejemplo para demostrar esto:
#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;
}
Obsérvelo en acción con el bit setuid en el programa mencionado eliminado:
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
Solo tengo algunas ideas sobre cómo solucionar este problema:
1) Reemplace el programa con un esqueleto que simplemente devuelve 0.
2) Parche grantpt () en mi libc para no hacer nada.
Puedo automatizar ambos, pero ¿alguien tiene una recomendación para uno sobre el otro, o recomendaciones sobre cómo resolver esto?
Una vez que esto se resuelva, finalmente puedo mount -o remount,nosuid /
.
fuente
pty
(como debe ser), pero para el programa?Respuestas:
Si su glibc está razonablemente actualizado y los dispositivos están configurados correctamente, no debería haber necesidad de invocar al
pt_chown
ayudante.Es posible que se encuentre con un problema conocido / potencial al eliminar setuid-root de
pt_chown
.grantpt()
admitidosdevfs
desde glibc-2.7 , se realizaron cambios en glibc-2.11, sin embargo, en lugar de verificarlo explícitamenteDEVFS_SUPER_MAGIC
, verifica si necesita hacer algún trabajo antes de intentarchown()
o recurrir a la invocaciónpt_chown
.Desde
glibc-2.17/sysdeps/unix/grantpt.c
Se usa una estrofa similar para verificar el gid y los permisos. El problema es que el uid, el gid y el modo deben coincidir con las expectativas (usted, tty y exactamente 620; confirme con
/usr/libexec/pt_chown --help
). Si no,chown()
(que requeriría capacidades CAP_CHOWN, CAP_FOWNER del binario / proceso que realiza la llamada) se intenta, y si eso falla, se intenta elpt_chown
ayudante externo (que debe ser setuid-root). Parapt_chown
poder usar capacidades, debe haber sido compilado con él (y por lo tanto su glibc)HAVE_LIBCAP
. Sin embargo , parece quept_chown
es (a partir de glibc-2.17 , y como notó aunque no ha indicado la versión) codificado para querergeteuid()==0
independientemente delHAVE_LIBCAP
código relevante deglibc-2.17/login/programs/pt_chown.c
:(Esperar
geteuid()==0
antes de intentar usar las capacidades no parece estar realmente en el espíritu de las capacidades, iría registrando un error en este caso).Una posible solución podría ser dar CAP_CHOWN, CAP_FOWNER a los programas afectados, pero realmente no lo recomiendo ya que no puede restringir eso a ptys, por supuesto.
Si eso no te ayuda a resolverlo, parchar
sshd
yscreen
es un poco menos desagradable que parchear glibc. Sin embargo, dado que el problema radica en glibc, un enfoque más limpio sería el uso selectivo de la inyección de DLL para implementar un maniquígrantpt()
.fuente