Я пытаюсь понять, как возможности Linux передаются процессу, который был exec()
'использован другим процессом. Из того, что я читал, для того, чтобы возможность сохранилась после exec, она должна быть в наследуемом наборе. Однако я не уверен, как этот набор заполняется.
Моя цель — иметь возможность запускать программу как обычный пользователь, который обычно требует root. Необходимая ей возможность — cap_dac_override
читать личный файл. Я не хочу давать ей никаких других возможностей.
Вот моя обертка:
#include <unistd.h>
int main(int argc, char *argv[]) {
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
Это работает, когда я устанавливаю разрешение setuid для полученного исполняемого файла:
~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns
Successfully registered hostname with DNS
Я бы хотел использовать capabilities вместо setuid. Я пробовал устанавливать capabilities cap_dac_override
в обертке:
~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ ./registerdns
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database
Я также попробовал установить флаг наследуемости для cap_dac_override
возможности 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
Мне нужно использовать оболочку, чтобы гарантировать, что эта возможность будет доступна только при использовании именно этого набора аргументов; программа net
выполняет ряд других действий, предоставление пользователям слишком широких прав доступа к ней может быть опасным.
Я, очевидно, не понимаю, как работает наследование. Я не могу понять, как настроить обертку, чтобы передать ее возможности процессу замены, чтобы он мог их использовать. Я прочитал страницу руководства и бесчисленное множество других документов о том, как этодолженработа, и я думал, что делаю то, что там описано.
решение1
Оказывается, установка +i на обертке делаетнетдобавить возможность в CAP_INHERITABLE
набор для процесса-обертки, таким образом, он не передается exec
. Поэтому мне пришлось вручную добавить CAP_DAC_OVERRIDE
перед CAP_INHERITABLE
вызовом 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);
}
Кроме того, мне пришлось добавить cap_dac_override
к разрешенным возможностям файла набор /usr/bin/net
и установить эффективный бит:
~ $ 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
Думаю, теперь я полностью понимаю, что происходит:
- Обертке необходим
CAP_DAC_OVERRIDE
разрешенный набор, чтобы она могла добавить его в свой наследуемый набор. - Наследуемый набор процесса оболочки отличается от наследуемого набора файла, поэтому установка +i для файла бесполезна; оболочка должна явно добавить
CAP_DAC_OVERRIDE
использованиеCAP_INHERITABLE
/ .cap_set_flag
cap_set_proc
- Файл
net
должен иметьCAP_DAC_OVERRIDE
в своем наследуемом наборе, чтобы он мог фактически наследовать возможности от оболочки в свойCAP_PERMITTED
набор. Также необходимо установить эффективный бит, чтобы он автоматически был повышен доCAP_EFFECTIVE
.
решение2
Я думаю, вам нужно и то, и другое:
setcap cap_dac_override+pe ./registerdns
setcap cap_dac_override+i /usr/bin/net
Флаги pe
on registerdns
говорят, что запуск программы приобретает возможность. Флаг i
on net
говорит, что разрешено наследовать возможность от вызывающей программы.