Возможности процесса Linux пусты, несмотря на то, что они установлены в исполняемом файле

#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 отслеживаемого двоичного файла.