#c #linux #linux-capabilities
#c #linux #linux-возможности
Вопрос:
У меня есть программа-оболочка, которая используется только для добавления CAP_NET_RAW
возможностей в скрипт nodejs. В двоичном файле установлены возможности cap_net_raw eip
, но процесс их не получает, и их установка вызывает EPERM (Operation not permitted)
. Оболочка перестала работать после обновления с Debian 9 до 10. Добавление возможности в двоичный файл nodejs работает, и скрипт nodejs работает нормально, но нежелательно разрешать необработанный доступ к сетевым адаптерам любому скрипту nodejs.
Вот исходный код оболочки:
#include <sys/capability.h>
#include <unistd.h>
void main() {
cap_t caps = cap_get_proc();
cap_value_t newcaps[1] = { CAP_NET_RAW, };
cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
cap_set_proc(caps);
cap_free(caps);
execl("/usr/bin/node", "node", "/opt/sitemp/sitemp.js", NULL);
}
Запуск его в strace приводит к следующему:
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, NULL) = 0
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=0, permitted=0, inheritable=0}) = 0
capset({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=0, permitted=0, inheritable=1<<CAP_NET_RAW}) = -1 EPERM (Operation not permitted)
Комментарии:
1. Я решил свою проблему, назначив эту возможность в systemd.service вместо пользовательской оболочки / двоичного файла. Службы Systemd имеют атрибут
AmbientCapabilities
, используемый именно для этого2. Ядро Linux не доверяет скриптам с правами доступа к файлам, только скомпилированным двоичным файлам. Та же проблема возникнет, если вы попытаетесь создать
sitemp.js
setuid-root.3. Привилегии устанавливаются для двоичного файла, а не для скрипта. Эта настройка работала в Debian 9, но не в 10.
4. Вместо того, чтобы пытаться привести здесь объяснение, я опубликую более полный ответ…
Ответ №1:
Слишком долго для комментария, вот более полное объяснение.
Во-первых, возможности файлов работают только с двоичными файлами.
Давайте вызовем вашу программу-оболочку wrapper.c
(скомпилированную как wrapper
). Для чего он закодирован, так это для создания наследуемых возможностей. Способ, которым наследуемые возможности могут привести к тому, что впоследствии выполняемая программа будет иметь привилегии, — это они И с возможностями «file Inheritable» в исполняемом файле.
То есть вы могли бы сделать это:
$ sudo setcap cap_net_raw=p ./wrapper
$ sudo setcap cap_net_raw=ie /usr/bin/node
Теперь, когда вы выполняете ./wrapper
, это вызовет наследуемую возможность, а когда это execl()
/usr/bin/node
произойдет, комбинация унаследует и повысит cap_net_raw
возможности в разрешенных и эффективных флагах запущенной /usr/bin/node
программы.
Если вы не используете ./wrapper
, у вас не будет возможности, наследуемой процессом, и /usr/bin/node
вы не унаследуете никаких привилегий.
Кроме того, вы можете очистить эти возможности и изменить wrapper.c
их, чтобы они выглядели следующим образом:
#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>
#include <unistd.h>
void main() {
cap_iab_t iab = cap_iab_from_text("^cap_net_raw");
if (iab == NULL) {
perror("iab not parsed");
exit(1);
}
if (cap_iab_set_proc(iab)) {
perror("unable to set iab");
exit(1);
}
cap_free(iab);
execl("/usr/bin/node", "node", "/opt/sitemp/sitemp.js", NULL);
perror("execl failed");
}
Вам нужно будет скомпилировать и настроить эту версию wrapper
следующим образом:
$ sudo setcap -r /usr/bin/node
$ cc -o wrapper wrapper.c -lcap
$ sudo setcap cap_net_raw,cap_setpcap=p ./wrapper
Теперь, когда вы запускаете ./wrapper
его, он поднимает как внешние, так и наследуемые возможности, и комбинация приведет /usr/bin/node
к наследованию некоторых привилегий напрямую ./wrapper
.
Комментарии:
1. вероятно, у вас опечатка в
have privilege is they AND with
2. Можете ли вы объяснить, чем это отличается от моего старого решения и почему оно работало в debian 9 и не работает в debian 10? В моем двоичном файле была установлена возможность, но
cap_set_proc
возвращена ошибка.3. Опечатки нет.. Это логическое И. Что касается того, как то, что вы пытались, когда-либо работало в более ранней версии Debian, я не могу догадаться. Без наследуемой возможности в двоичном файле узла наследуемая возможность процесса не может предоставлять никаких привилегий. Это было верно в ядре с момента добавления файловых возможностей.
4. почему оболочка, имея
cap_net_raw=eip
, получаетEPERM
при вызовеcap_set_proc
? Дажеcap_get_proc
не возвращает никаких возможностей5. Если вы запускаете его под
strace
, его привилегии подавляются. Ядро делает это, чтобы предотвратить повышение привилегий, поскольку необходимые для запуска API ядраstrace
могут фактически изменять поведение./wrapper
отслеживаемого двоичного файла.