J'administre une boîte Gentoo Hardened qui utilise les capacités des fichiers pour éliminer la plupart des binaires setuid-root (par exemple /bin/ping
a CAP_NET_RAW, etc.).
En fait, le seul binaire qu'il me reste est celui-ci:
abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ #
Si je supprime le bit setuid ou remonte mon système de fichiers racine nosuid
, sshd et GNU Screen cessent de fonctionner, car ils appellent grantpt(3)
leurs maîtres pesudoterminals et glibc exécute apparemment ce programme pour afficher et chmod le pseudoterminal esclave sous /dev/pts/
, et GNU Screen se soucie quand cette fonction échoue.
Le problème est que la page de manuel de grantpt(3)
explicitement indique que sous Linux, avec le devpts
système de fichiers monté, aucun binaire d'assistance n'est requis; le noyau définira automatiquement l'UID et le GID de l'esclave sur le véritable UID et GID du processus qui s'est ouvert /dev/ptmx
(en appelant getpt(3)
).
J'ai écrit un petit exemple de programme pour le démontrer:
#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;
}
Observez-le en action avec le bit setuid sur le programme susmentionné supprimé:
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
Je n'ai que quelques idées sur la façon de contourner ce problème:
1) Remplacez le programme par un squelette qui renvoie simplement 0.
2) Patch grantpt () dans ma libc pour ne rien faire.
Je peux automatiser les deux, mais quelqu'un a-t-il une recommandation à faire l'un par rapport à l'autre, ou des recommandations sur la manière de résoudre ce problème?
Une fois que cela est résolu, je peux enfin mount -o remount,nosuid /
.
la source
pty
(comme ils le devraient) mais le programme?Réponses:
Si votre glibc est raisonnablement à jour et que devpts est correctement configuré, il ne devrait pas du tout être nécessaire d'appeler l'
pt_chown
assistant.Vous rencontrez peut-être un problème connu / potentiel supprimant setuid-root
pt_chown
.grantpt()
pris en chargedevfs
par glibc-2.7 , des modifications ont été apportées à glibc-2.11, de sorte que plutôt que de vérifier explicitementDEVFS_SUPER_MAGIC
, il vérifie plutôt s'il doit faire un travail avant d'essayerchown()
ou de revenir à l'invocationpt_chown
.De
glibc-2.17/sysdeps/unix/grantpt.c
Une strophe similaire est utilisée pour vérifier le gid et les autorisations. Le hic est que l'uid, le gid et le mode doivent correspondre aux attentes (vous, tty et exactement 620; confirmez avec
/usr/libexec/pt_chown --help
). Sinon,chown()
(ce qui nécessiterait des capacités CAP_CHOWN, CAP_FOWNER du binaire / processus appelant) est tenté, et si cela échoue, l'pt_chown
assistant externe (qui doit être setuid-root) est tenté. Pourpt_chown
pouvoir utiliser les capacités, il (et donc votre glibc) doit avoir été compilé avecHAVE_LIBCAP
. Cependant , il semble quept_chown
(à partir de la glibc-2.17 , et comme vous l'avez remarqué bien que vous n'ayez pas indiqué la version) codé en dur à vouloirgeteuid()==0
indépendamment duHAVE_LIBCAP
code pertinent deglibc-2.17/login/programs/pt_chown.c
:(Attendre
geteuid()==0
avant d'essayer d'utiliser des capacités ne semble pas vraiment dans l'esprit des capacités, j'irais avec l'enregistrement d'un bug sur celui-ci.)Une solution de contournement potentielle pourrait être de donner CAP_CHOWN, CAP_FOWNER aux programmes concernés, mais je ne le recommande vraiment pas car vous ne pouvez pas limiter cela aux ptys bien sûr.
Si cela ne vous aide pas à le résoudre, le rapiéçage
sshd
etscreen
est un peu moins désagréable que glibc rapiéçage. Étant donné que le problème réside dans la glibc, une approche plus propre serait l' utilisation sélective de l'injection de DLL pour implémenter un mannequingrantpt()
.la source