Estoy tratando de entender cómo se pasan las capacidades de Linux a un proceso que ha sido exec()
controlado por otro. Por lo que he leído, para que una capacidad se mantenga después de la ejecución, debe estar en el conjunto heredable. Sin embargo, de lo que no estoy seguro es de cómo se completa ese conjunto.
Mi objetivo es poder ejecutar un programa como usuario normal que normalmente requeriría root. La capacidad que necesita es cap_dac_override
poder leer un archivo privado. No quiero darle ninguna otra capacidad.
Aquí está mi envoltorio:
#include <unistd.h>
int main(int argc, char *argv[]) {
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
Esto funciona cuando configuro el permiso setuid en el ejecutable resultante:
~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns
Successfully registered hostname with DNS
Sin embargo, me gustaría usar capacidades en lugar de setuid. Intenté configurar la cap_dac_override
capacidad en el contenedor:
~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ ./registerdns
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database
También intenté configurar el indicador heredable en la cap_dac_override
capacidad del net
ejecutable en sí:
~ $ 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
Necesito usar el contenedor para asegurarme de que la capacidad solo esté disponible cuando se usa ese conjunto exacto de argumentos; El net
programa hace varias otras cosas que podrían ser peligrosas si otorga a los usuarios permisos demasiado amplios.
Obviamente no entiendo bien cómo funciona la herencia. Parece que no puedo entender cómo configurar el contenedor para pasar sus capacidades al proceso de reemplazo para que pueda usarlas. He leído la página de manual y muchos otros documentos sobre cómodeberíatrabajo, y pensé que estaba haciendo lo que describe.
Respuesta1
Resulta que configurar +i en el contenedor nonoagregue la capacidad al CAP_INHERITABLE
conjunto para el proceso contenedor, por lo que no se pasa exec
. Por lo tanto, tuve que agregar manualmente CAP_DAC_OVERRIDE
antes CAP_INHERITABLE
de llamar 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);
}
Además, tuve que agregar cap_dac_override
a las capacidades de archivo permitidas configuradas /usr/bin/net
y configurar el bit efectivo:
~ $ 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
Creo que ahora entiendo completamente lo que está pasando:
- El contenedor necesita
CAP_DAC_OVERRIDE
su conjunto permitido para poder agregarlo a su conjunto heredable. - El conjunto heredable del proceso del contenedor es diferente al conjunto heredable del archivo, por lo que configurar +i en el archivo es inútil; el contenedor debe agregarse explícitamente
CAP_DAC_OVERRIDE
alCAP_INHERITABLE
uso decap_set_flag
/cap_set_proc
. - El
net
archivo debe estarCAP_DAC_OVERRIDE
en su conjunto heredable para que de hecho pueda heredar la capacidad del contenedor en suCAP_PERMITTED
conjunto. También es necesario configurar el bit efectivo para que se promocione automáticamente aCAP_EFFECTIVE
.
Respuesta2
Creo que necesitas ambos:
setcap cap_dac_override+pe ./registerdns
setcap cap_dac_override+i /usr/bin/net
Las pe
banderas encendidas registerdns
dicen que ejecutar el programa adquiere la capacidad. La i
bandera encendida net
dice que se le permite heredar la capacidad del programa que realiza la llamada.