Passando capacidades através do exec

Passando capacidades através do exec

Estou tentando entender como os recursos do Linux são passados ​​para um processo que foi feito exec()por outro. Pelo que li, para que um recurso seja mantido após exec, ele deve estar no conjunto herdável. O que não tenho certeza, porém, é como esse conjunto é preenchido.

Meu objetivo é ser capaz de executar um programa como um usuário normal que normalmente exigiria root. A capacidade necessária é cap_dac_overridepara poder ler um arquivo privado. Não quero dar-lhe quaisquer outras capacidades.

Aqui está meu invólucro:

#include <unistd.h>

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

Isso funciona quando eu 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 capacidades em vez de setuid. Tentei definir a cap_dac_overridecapacidade 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

Também tentei definir o sinalizador herdável na cap_dac_overridecapacidade do netpróprio executável:

~ $ 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

Preciso usar o wrapper para garantir que o recurso esteja disponível apenas ao usar esse conjunto exato de argumentos; o netprograma faz várias outras coisas que podem ser perigosas para conceder aos usuários permissões muito amplas.

Obviamente estou entendendo mal como funciona a herança. Não consigo descobrir como configurar o wrapper para transmitir seus recursos ao processo de substituição para que ele possa usá-los. Eu li a página de manual e inúmeros outros documentos sobre como issodevetrabalho, e pensei que estava fazendo o que descreve.

Responder1

Acontece que definir +i no wrapper faznãoadicione a capacidade ao CAP_INHERITABLEconjunto para o processo wrapper, portanto, ela não será transmitida exec. Portanto, tive que adicionar manualmente CAP_DAC_OVERRIDEantes CAP_INHERITABLEde ligar 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_overriderecursos de arquivo permitidos /usr/bin/nete 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 perfeitamente o que está acontecendo:

  1. O wrapper precisa CAP_DAC_OVERRIDEde seu conjunto permitido para poder adicioná-lo ao seu conjunto herdável.
  2. O conjunto herdável do processo do wrapper é diferente do conjunto herdável do arquivo, portanto, definir +i no arquivo é inútil; o wrapper deve adicionar explicitamente CAP_DAC_OVERRIDEao CAP_INHERITABLEuso de cap_set_flag/ cap_set_proc.
  3. O netarquivo precisa estar CAP_DAC_OVERRIDEem seu conjunto herdável para que possa de fato herdar a capacidade do wrapper em seu CAP_PERMITTEDconjunto. Ele também precisa que o bit efetivo seja definido para que seja automaticamente promovido para CAP_EFFECTIVE.

Responder2

Acho que você precisa de ambos:

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

Os pesinalizadores registerdnsindicam que a execução do programa adquire a capacidade. A ibandeira netindica que é permitido herdar a capacidade do programa de chamada.

informação relacionada