Passando recursos através do exec

6

Estou tentando entender como os recursos do Linux são passados para um processo que foi exec() d por outro. Pelo que tenho lido, para que uma capacidade seja mantida após o exec, ela deve estar no conjunto herdável. O que eu não tenho certeza é como esse conjunto é preenchido.

Meu objetivo é poder executar um programa como um usuário comum que normalmente precisaria de root. A capacidade necessária é de cap_dac_override para que possa ler um arquivo privado. Eu não quero dar a ele nenhum outro recurso.

Aqui está meu wrapper:

#include <unistd.h>

int main(int argc, char *argv[]) {
    return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}

Isso funciona quando defino a permissão setuid no executável resultante:

~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns 
Successfully registered hostname with DNS

Eu gostaria de usar recursos em vez de setuid, no entanto. Eu tentei definir o recurso cap_dac_override no wrapper:

~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ ./registerdns 
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database

Eu também tentei definir o sinalizador herdável no recurso cap_dac_override para o próprio executável net :

~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ sudo setcap cap_dac_override=i /usr/bin/net
~ $ ./registerdns 
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database

Eu preciso usar o wrapper para garantir que o recurso esteja disponível somente ao usar esse conjunto exato de argumentos; O programa net faz várias outras coisas que podem ser perigosas para dar aos usuários permissões muito amplas.

Eu obviamente não entendi como a herança funciona. Eu não consigo descobrir como configurar o wrapper para passar seus recursos ao processo de substituição para que ele possa usá-los. Eu li a página man, e inúmeros outros documentos sobre como deve funcionar, e eu pensei que estava fazendo o que descreve.

    
por AdmiralNemo 08.05.2014 / 01:17

2 respostas

6

Acontece que a configuração + i no wrapper não não adiciona o recurso ao CAP_INHERITABLE definido para o processo do wrapper, portanto, ele não é passado por exec . Portanto, tive que adicionar manualmente CAP_DAC_OVERRIDE a CAP_INHERITABLE antes de chamar execl :

#include <sys/capability.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv[]) {
    cap_t caps = cap_get_proc();
    printf("Capabilities: %s\n", cap_to_text(caps, NULL));
    cap_value_t newcaps[1] = { CAP_DAC_OVERRIDE, };
    cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
    cap_set_proc(caps);
    printf("Capabilities: %s\n", cap_to_text(caps, NULL));
    cap_free(caps);
    return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}

Além disso, tive que adicionar cap_dac_override aos recursos de arquivo permitidos definidos em /usr/bin/net e definir o bit efetivo:

~ $ sudo setcap cap_dac_override=p ./registerdns
~ $ sudo setcap cap_dac_override=ei /usr/bin/net
~ $ ./registerdns
Capabilities = cap_dac_override+p
Capabilities = cap_dac_override+ip
Successfully registered hostname with DNS

Acho que agora entendo completamente o que está acontecendo:

  1. O wrapper precisa de CAP_DAC_OVERRIDE em seu conjunto permitido para poder adicioná-lo ao conjunto herdável.
  2. O conjunto herdável do processo do wrapper é diferente do conjunto herdado do arquivo, portanto, a configuração + i no arquivo é inútil; o wrapper deve incluir explicitamente CAP_DAC_OVERRIDE to CAP_INHERITABLE usando cap_set_flag / cap_set_proc .
  3. O arquivo net precisa ter CAP_DAC_OVERRIDE em seu conjunto herdável para poder herdar o recurso do wrapper no seu CAP_PERMITTED set. Ele também precisa que o bit efetivo seja definido para que seja promovido automaticamente para CAP_EFFECTIVE .
por 16.05.2014 / 01:36
1

Eu acho que você precisa de ambos:

setcap cap_dac_override+pe ./registerdns
setcap cap_dac_override+i /usr/bin/net

Os pe sinalizadores em registerdns dizem que a execução do programa adquire a capacidade. O sinal i em net diz que é permitido herdar o recurso do programa de chamada.

    
por 09.05.2014 / 21:10