Не удалось заставить CAP_CHOWN и CAP_DAC_OVERRIDE работать для обычного пользователя

Мое требование

Мой сервер python работает как обычный пользователь на RHEL, но ему нужно создавать файлы/каталоги в местах, к которым у него нет доступа. Также необходимо сделать chown для этих файлов со случайным UID/GID.

Мой подход

Попробуйте это в среде только для возможностей, без setuid. Я пытаюсь использовать возможности cap_chown и cap_dac_override. Но я совершенно не понимаю, как заставить его работать в среде типа systemctl.

В настоящее время у меня есть следующее в файле службы:

#cat /usr/lib/systemd/system/my_server.service 

[Service]
Type=simple
SecureBits=keep-caps
User=testuser
CapabilityBoundingSet=~
Capabilities=cap_dac_override,cap_chown=eip
ExecStart=/usr/bin/linux_capability_test.py

И далее по самому бинарнику:

# getcap /usr/bin/linux_capability_test.py
/usr/bin/linux_capability_test.py = cap_chown,cap_dac_override+ei

Но здесь говорится, что он никогда не будет работать со сценариями: to-privived-ports-1024-on-l#414258">Есть ли способ привязки процессов без полномочий root к привилегированным портам в Linux?

С текущими настройками у меня есть следующие возможности для запущенного процесса:

# ps -ef | grep lin
testuser    28268     1  0 22:31 ?        00:00:00 python /usr/bin/linux_capability_test.py

# getpcaps 28268
Capabilities for `28268': = cap_chown,cap_dac_override+i

Но если я попытаюсь создать файл в /etc/ из этого скрипта:

try:
    file_name = '/etc/junk'
    with open(file_name, 'w') as f:
        os.utime(file_name,None)

Сбой с «Отказано в доступе»

Это тот же случай для меня, что это не будет работать? Могу ли я использовать здесь модуль python-prctl, чтобы он заработал?


person mittal    schedule 07.08.2015    source источник


Ответы (3)


setuid не будет работать со сценариями, потому что это дыра в безопасности из-за способа выполнения сценариев. Об этом есть несколько документов. Вы даже можете начать с просмотра страницы в Википедии.

Действительно хороший обходной путь — написать небольшую программу на C, которая запустит ваш скрипт Python с жестко заданными путями к python и скрипту. Действительно хорошее обсуждение всех проблем можно найти здесь

person Patrick Maupin    schedule 08.08.2015
comment
Спасибо за ваш ответ и ссылку. Но я думаю, что специально хочу избегать setuid в сценариях, поэтому хочу использовать только «возможности Linux». о чем мой вопрос - person mittal; 08.08.2015

Обновление: метод для этого, не уверен, что лучший. Использование модуля «python-prctl»:

1. Ditch 'User=testuser' from my-server.service
2. Start server as root
3. Set 'keep_caps' flag True
4. Do 'setgroups, setgid and setuid'
5. And immediately limit the permitted capability set to 'DAC_OVERRIDE' and 'CHOWN' capability only
6. Set the effective capability for both to True

Вот код для того же

import prctl

prctl.securebits.keep_caps = True

os.setgroups([160])
os.setgid(160)
os.setuid(160)

prctl.cap_permitted.limit(prctl.CAP_CHOWN, prctl.CAP_DAC_OVERRIDE)
prctl.cap_effective.dac_override = True
prctl.cap_effective.chown = True`

ГОТОВО!!

person mittal    schedule 08.08.2015
comment
Итак, теперь вы используете весь свой сервер с CAP_CHOWN? - person Patrick Maupin; 08.08.2015
comment
Да, здесь есть оговорка. Но я думаю, что моя первоначальная попытка установить возможности в файле .service и т. д. также пыталась сделать то же самое, установить возможности на всем сервере. Вы упомянули в своем комментарии напишите небольшую программу на C, которая запустит ваш скрипт Python с жестко запрограммированными путями к python и скрипту. Я не понял эту часть. В ссылке, которую вы упомянули, в каком разделе я должен искать пример? - person mittal; 08.08.2015
comment
Существует раздел, который начинается. Ответ на этот вопрос заключается в использовании двоичного файла setuid для выполнения сценария. Но если вы передадите возможность случайного сценария chown, все, что ему нужно сделать, это изменить и отредактировать пару файлов в /etc, а затем он сможет выполнять все, что захочет, как часть задания cron. Вам нужен новый пользователь для вашего chown, и вы хотите, чтобы он был очень изолирован. См., например, этот ответ. - person Patrick Maupin; 08.08.2015
comment
Хорошо, тот раздел. Итак, в моем случае двоичный файл с setuid 0, если запускает сервер Python, а сервер в любом случае снова выполняет setuid (regular_user), он снова потеряет возможность, верно? Я полностью понимаю проблему безопасности и поднял то же самое с нашими людьми ;) Вторая ссылка, которую вы разместили, - это именно то, что я имел в виду как альтернативный подход. В моем случае серверу (также серверу REST) ​​может потребоваться перезаписать/изменить/удалить файлы, принадлежащие любому пользователю, а также передать их любому другому. Как предоставить возможности отдельному пользователю? - person mittal; 08.08.2015
comment
В зависимости от того, какая у вас версия Linux, вы, , возможно, не сможете чтобы дать возможность пользователям напрямую. Но вы, безусловно, можете добавить желаемые возможности к разрешенным и наследуемым возможностям небольшой программы на C. Если вы можете делать все, что вам нужно, в небольшой программе на C, вам может не понадобиться SETUID. Если вам нужно вызвать сценарий из программы, вы, безусловно, должны изолировать сценарий, поставив его и программу C под контроль отдельного пользователя. - person Patrick Maupin; 08.08.2015
comment
вы, безусловно, можете добавить желаемые возможности к разрешенным и наследуемым возможностям небольшой программы на C. Если вы можете делать все, что вам нужно, в небольшой программе на языке C, вам может не понадобиться SETUID. Программа на языке C будет в основном выполнять только операции копирования/перемещения/удаления и chown. Чтобы добиться этого, как мне указать возможности? В самой программе, внутри программы, перед вызовом программы с сервера? Извините, если я прошу слишком много информации - person mittal; 08.08.2015
comment
Используйте программу setcap для исполняемого файла. - person Patrick Maupin; 08.08.2015

Основываясь на нашем обсуждении выше, я сделал следующее:

[Service]
Type=simple
User=testuser
SecureBits=keep-caps
Capabilities=cap_chown,cap_dac_override=i
ExecStart=/usr/bin/linux_capability_test.py

Это запускает сервер с обеими этими возможностями как наследуемыми.

Написал небольшой C, тестовый код для файла chown

#include <unistd.h>

int main()
  {
    int ret = 0;

    ret = chown("/etc/junk", 160, 160);

    return ret;
  }

Установите следующий двоичный файл gcc

chown testuser:testuser /usr/bin/chown_c
chmod 550 /usr/bin/chown_c
setcap cap_chown,cap_dac_override=ie /usr/bin/chown_c

Сервер делает следующее, чтобы вызвать двоичный файл

import prctl
prctl.cap_inheritable.chown = True
prctl.cap_inheritable.dac_override = True
execve('/usr/bin/chown_c',[],os.environ)

И я смог получить желаемый результат

# ll /etc/junk 
-rw-r--r-- 1 root root 0 Aug  8 22:33 /etc/junk

# python capability_client.py 

# ll /etc/junk 
-rw-r--r-- 1 testuser testuser 0 Aug  8 22:33 /etc/junk
person mittal    schedule 08.08.2015