Установка разрешений только root для файлов /dev и сборка двоичных файлов

В рамках процесса сборки я хочу запустить следующие две команды:

sudo chmod a+r /dev/cpu/*/msr
sudo setcap cap_sys_rawio=ep ./bench

Это устанавливает для файлов /dev/cpu/*/msr, предоставляемых модулем ядра msr, доступ для чтения всем, а также устанавливает дополнительные разрешения для двоичного файла ./bench (созданного как часть сборки), необходимые для фактического чтения этих файлов.

Проблема в том, что для этого требуются права root, поэтому файл sudo.

Я бы хотел что-то вроде корневого скрипта setuid, который выполняет эти две конкретные вещи, но setuid root скрипты не рекомендуются и отключаются в современных Linux.

Каковы мои варианты здесь для простого решения?

Решение, которое работает только для второй строки (setcap), также интересно, потому что оно мне нужно для запуска каждой сборки, а chmod нужно запускать только один раз за загрузку.


person BeeOnRope    schedule 13.01.2020    source источник


Ответы (3)


Достичь того же с помощью libcap на самом деле не так уж много кода :

#include <stdio.h>
#include <sys/capability.h>

int main(int arc, char *argv[]) {
    cap_t c = cap_from_text("cap_sys_rawio=ep");
    int status = cap_set_file("./bench", c);
    cap_free(c);
    if (status)
        perror("attempt failed");
    return status != 0;
}

Чтобы скомпилировать это (в Debian вам понадобится sudo apt-get install libcap-dev; в Fedora sudo dnf install libcap-devel):

$ gcc -o mkcap mkcap.c -lcap

Если вы просто запустите его как есть, он потерпит неудачу, поскольку программа должна иметь достаточные привилегии, чтобы фактически добавить возможность в ./bench:

$ ./mkcap
attempt failed: Operation not permitted

Итак, вам нужно сделать его достаточно дееспособным:

$ sudo /sbin/setcap cap_setfcap=ep ./mkcap
$ ./mkcap
$ echo $?
0
  • Возможно, вы захотите указать более явный путь к двоичному файлу "./bench", поскольку, в зависимости от вашей среды, вы можете опасаться, что кто-то может злоупотребить mkcap, чтобы передать cap_sys_rawio какой-либо другой программе. Использование полного пути было бы менее двусмысленным.
  • Вы также можете chmod go-x ./mkcap ограничить круг лиц, которые могут его запускать.
  • Вы также можете рассмотреть возможность использования наследуемых возможностей для всего этого:
basic $ sudo setcap cap_setfcap=ei ./mkcap
basic $ ./mkcap
attempt failed: Operation not permitted
basic $ sudo capsh --inh=cap_setfcap --user=$(whoami) --
enhanced $ ./mkcap
enhanced $ echo $?
0

На уровне enhanced (оболочка capsh) вы можете повысить эту возможность для двоичных файлов, у которых установлен бит наследуемого файла. Таким образом, оболочки слоя basic по умолчанию не могут получить никаких привилегий из mkcap. Во всех остальных отношениях слой оболочки enhanced идентичен слою basic. Например, вы можете выполнять сборки и делать все как обычно. (Используйте exit, чтобы выйти из оболочки enhanced.)

Существует модуль pam_cap, который также может добавлять наследуемый бит ко всем оболочкам определенных пользователей при входе в систему и т. д.

person Tinkerer    schedule 10.04.2021
comment
cap_free может установить errno; возможно, лучше проверить status и запустить perror сразу после cap_set_file. - person Peter Cordes; 10.04.2021
comment
В данном конкретном случае я думаю, что на самом деле безопасно этого не делать. Если cap_free() работает с допустимым указателем, то он не установит errno. Если он работает с чем-то другим, потому что функция cap_from_text() не удалась, напечатанное 'perror()' будет более информативным. - person Tinkerer; 11.04.2021

Вы можете создать простую программу на C для использования вместо сценария оболочки:

#include <stdio.h>
#include <unistd.h>

int main(void) {
    char *const envp[] = {NULL};
    execle("/sbin/setcap", "setcap", "cap_sys_rawio=ep", "./bench", NULL, envp);
    perror("execle");
    return 1;
}

Заметки:

  • Это безопасно, поскольку игнорирует свою среду (включая PATH) и не вызывает оболочку, но его все равно можно запустить из любого места, поэтому нет никакой гарантии, что именно ./bench есть. Вы можете жестко указать абсолютный путь.
  • Вы можете использовать тот же трюк для запуска нескольких команд, но тогда вам нужно попасть в fork и wait. (Не используйте system, так как это вызывает оболочку и не позволяет запретить сценарии setuid!)
  • Вместо вызова двоичного файла setcap вы можете использовать функции libcap вместо этого, но это было бы немного сложнее.
  • Вы можете использовать glob для расширения /dev/cpu/*/msr, как это делает оболочка, если вы хотите сделать первую часть, а затем stat и chown, чтобы избежать необходимости exec.
person Joseph Sible-Reinstate Monica    schedule 13.01.2020
comment
Спасибо, мне не хватало уловки, заключавшейся в простом способе запуска команд оболочки из C. Я знал, что вы можете написать программу на C, но я не хотел кропотливо преобразовывать сценарий оболочки в системные вызовы (что иногда очень сложно, когда основной процесс выполняет большую работу). - person BeeOnRope; 14.01.2020

Как уже говорилось, использование libcap — хороший вариант установки возможностей. Для доступа к MSR без прав sudo я предлагаю использовать msr-safe. Он был реализован для Intel, однако я успешно протестировал его и для AMD. После загрузки модуля ядра msr_safe появится несколько новых файлов. Вместо доступа к msrs через /dev/cpu/*/msr вы будете использовать /dev/cpu/*/msr_safe. Он откроет вам регистры, перечисленные в /dev/cpu/msr_allowlist (ранее msr_whitelist). Вы также можете контролировать, какие биты этих регистров будут доступны для записи, с помощью маски в файле.

Кроме того, можно подготовить пакет (/dev/cpu/msr_batch) — список регистров, к которым вы будете обращаться повторно, что сократит накладные расходы. Эта функция реализована в libmsr.

person Andrew    schedule 09.07.2021