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

Я пытаюсь написать программу, которая требует повышенных возможностей (а не просто запускать ее с помощью sudo). Однако ни одна из возможностей, которые я установил с помощью setcap, похоже, не передается в процесс после его выполнения. Эта проблема возникает в нескольких исполняемых файлах и при использовании разных возможностей.

Этот код использует функцию cap_set_file(), чтобы предоставить возможность CAP_NET_RAW файлу, переданному как CLA. (Не спрашивайте меня, зачем мне это нужно.)

#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/capability.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define handle_error(msg) \ 
    do { printf("%s: %s\n", msg, strerror(errno)); exit(EXIT_FAILURE); } while (0)

void print_cap_buf(cap_t cur) {
    char *buf;
    buf = cap_to_text(cur, NULL);
    printf("%s\n", buf);
    cap_free(buf);
}

void get_and_print_cap_buf() {
    cap_t cur = cap_get_proc();
    print_cap_buf(cur);
    cap_free(cur);
}

int main(int argc, char *argv[]) {
    cap_t file_cap;

    printf("Process capabilities: ");
    get_and_print_cap_buf(); // Print the current process capability list.

    file_cap = cap_from_text("cap_net_raw=ep");
    if (file_cap == NULL) handle_error("cap_from_text");

    printf("Capabilities to set in file: "); print_cap_buf(file_cap);

    if (argc == 2) {
        if ( cap_set_file(argv[1], file_cap) != 0) handle_error("cap_set_file");
    } else printf("No file specified.\n");

    cap_free(file_cap);
    return 0;
}

После компиляции с помощью gcc:

gcc -Wall -pedantic -std=gnu99 test.c -o tt -lcap

Я даю ему возможности с:

sudo setcap "cap_setfcap,cap_fowner,cap_net_raw=eip" tt 

и с использованием getcap tt вывод:

 $ getcap tt
tt = cap_fowner,cap_net_raw,cap_setfcap+eip

Однако, когда я запускаю программу, я получаю следующий вывод (test-client — это исполняемый файл, который создает необработанный сокет Ethernet):

 $ ./tt test-client
Process capabilities: =
Capabilities to set in file: = cap_net_raw+ep
cap_set_file: Operation not permitted

ОДНАКО... когда я запускаю программу с помощью sudo, все возможности процесса работают нормально.

 $ sudo ./tt test-client
Process capabilities: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37+ep
Capabilities to set in file: = cap_net_raw+ep

и целевой файл «test-client» правильно устанавливает свои возможности.

Однако даже с CAP_NET_RAW клиент не может выполнить вызов socket() с помощью EPERM. Я попытался установить CAP_NET_ADMIN, если это также необходимо; такая же проблема. Я пытался использовать CAP_SETPCAP в программе выше; нет кости. Я почти уверен, что сузил его до какого-то разрыва, когда возможности исполняемого файла не влияют на работающий процесс.

Что мне здесь не хватает?


РЕДАКТИРОВАТЬ, на следующее утро:

Итак, я провел еще несколько тестов, и оказалось, что этот код отлично работает на Raspberry Pi. Я запускаю Lubuntu 16.04 с LXTerminal на своей основной машине, и это тот, который терпит неудачу. Он не работает внутри LXTerminal, а также в текстовой оболочке. Может это баг ОС?

Машина Lubuntu (cat /proc/version):

Linux version 4.4.0-34-generic (buildd@lgw01-20) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #53-Ubuntu SMP Wed Jul 27 16:06:39 UTC 2016

Пи:

Linux version 4.4.11-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #888 SMP Mon May 23 20:10:33 BST 2016

РЕДАКТИРОВАТЬ СНОВА: --

Протестировано на другом компьютере с тем же USB-ключом, который я использовал для установки. Немного отличается /proc/версия:

Linux version 4.4.0-31-generic (buildd@lgw01-16) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016

Работает отлично. Я весьма озадачен.


person Matt S    schedule 16.08.2016    source источник


Ответы (2)


Я, наконец, заставил это работать, благодаря информации, найденной здесь:

https://superuser.com/questions/865310/file-capabilities-setcap-not-being-applied-in-linux-mint-17-1

Оказывается, мой домашний каталог монтируется как nosuid, что отключает все флаги возможностей.

При запуске программы в файловой системе без nosuid она работает как положено.


Для будущих читателей: если вы столкнулись с этой проблемой, убедитесь, что ваша файловая система не смонтирована как nosuid. Используя команду mount, проверьте файловую систему, которая соответствует тому месту, где вы храните данные (в моем случае /home/user), и посмотрите, установлен ли флаг nosuid.

$ mount
...
/home/.ecryptfs/user/.Private on /home/user type ecryptfs (rw,nosuid,nodev,relatime,ecryptfs_fnek_sig=***,ecryptfs_sig=***,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_unlink_sigs)

(Это система ecryptfs, поэтому, если вы выбрали «Зашифровать мой домашний каталог» при установке Ubuntu, у вас, вероятно, возникнет эта проблема. Я не мог найти способ смонтировать это как suid, и, вероятно, не хотел бы в любом случае .)

В итоге я создал новый каталог /code (это моя файловая система, я могу делать, что хочу), который монтируется на другой раздел без nosuid.


Было бы неплохо, если бы справочные страницы для возможностей ссылались на этот факт... (редактировать: патч отправлен, теперь он есть :))

person Matt S    schedule 18.08.2016

Просто точка данных: ваш код работает здесь на более старой машине LTS:

$ uname  -vr
3.13.0-63-generic #103-Ubuntu SMP Fri Aug 14 21:42:59 UTC 2015

$ ./tt test-client
Process capabilities: = cap_fowner,cap_net_raw,cap_setfcap+ep
Capabilities to set in file: = cap_net_raw+ep

$ cat /etc/debian_version 
jessie/sid

Может быть, это как-то связано с возможностями пользовательского процесса (вызов ./tt)? Как сказано в возможностях (7), Возможности — это атрибут потока.

person James K. Lowden    schedule 16.08.2016