Eu administro uma caixa Gentoo Hardened que usa recursos de arquivo para eliminar a maior parte da necessidade de binários raiz setuid (por exemplo, /bin/ping
tem CAP_NET_RAW, etc).
De fato, o único binário que me resta é este:
abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ #
Se eu remover o bit setuid ou remontar meu sistema de arquivos raiz nosuid
, sshd e GNU Screen parem de funcionar, porque eles chamam grantpt(3)
seus pesudoterminals principais e a glibc aparentemente executa esse programa para mostrar e chmod o pseudoterminal escravo em baixo /dev/pts/
, e o GNU Screen se preocupa quando essa função falha.
O problema é que a página de manual grantpt(3)
declara explicitamente que, no Linux, com o devpts
sistema de arquivos montado, esse binário auxiliar não é necessário; o kernel definirá automaticamente o UID & GID do escravo como o verdadeiro UID & GID do processo que foi aberto /dev/ptmx
(chamando getpt(3)
).
Eu escrevi um pequeno programa de exemplo para demonstrar isso:
#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;
}
Observe-o em ação com o bit setuid no programa mencionado acima removido:
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
Eu tenho apenas algumas idéias sobre como solucionar esse problema:
1) Substitua o programa por um esqueleto que simplesmente retorne 0.
2) Patch grantpt () na minha libc para não fazer nada.
Posso automatizar os dois, mas alguém tem uma recomendação para um sobre o outro, ou recomendações sobre como resolver isso?
Uma vez resolvido, posso finalmente mount -o remount,nosuid /
.
fonte
pty
(como deveriam), mas o programa?Respostas:
Se sua glibc estiver razoavelmente atual e os devpts estiverem configurados corretamente, não será necessário chamar o
pt_chown
ajudante.Você pode estar enfrentando um problema conhecido / potencial ao remover o setuid-root
pt_chown
.grantpt()
Com suportedevfs
no glibc-2.7 , as alterações foram feitas no glibc-2.11, de modo que, emDEVFS_SUPER_MAGIC
vez de procurar explicitamente , ele verifica se precisa fazer algum trabalho antes de tentarchown()
ou voltar a invocarpt_chown
.A partir de
glibc-2.17/sysdeps/unix/grantpt.c
Uma estrofe semelhante é usada para verificar o gid e as permissões. O problema é que o uid, gid e mode devem corresponder às expectativas (você, tty e exatamente 620; confirme com
/usr/libexec/pt_chown --help
). Caso contrário,chown()
(o que exigiria os recursos CAP_CHOWN, CAP_FOWNER do binário / processo de chamada) é tentado e, se isso falhar, opt_chown
auxiliar externo (que deve ser configurado como raiz) é tentado. Parapt_chown
poder usar os recursos, ele (e, portanto, sua glibc) deve ter sido compiladoHAVE_LIBCAP
. No entanto , parece quept_chown
é (como no glibc-2.17 e, como você notou, embora você não tenha declarado a versão) codificado para querer,geteuid()==0
independentemente doHAVE_LIBCAP
código relevante deglibc-2.17/login/programs/pt_chown.c
:(Esperar que
geteuid()==0
antes de tentar usar recursos não pareça realmente com o espírito de recursos, eu iria registrar um bug nesse caso.)Uma solução potencial pode ser dar CAP_CHOWN, CAP_FOWNER aos programas afetados, mas eu realmente não recomendo isso, pois você não pode restringir isso aos ptys, é claro.
Se isso não ajudar a resolvê-lo, faça o patch
sshd
escreen
seja um pouco menos desagradável do que o patch glibc. Como o problema está na glibc, uma abordagem mais limpa seria o uso seletivo de injeção de DLL para implementar um manequimgrantpt()
.fonte