Python 2.7 无法使CAP_CHOWN和CAP_DAC_覆盖为普通用户工作

Python 2.7 无法使CAP_CHOWN和CAP_DAC_覆盖为普通用户工作,python-2.7,systemd,linux-capabilities,Python 2.7,Systemd,Linux Capabilities,我的要求 我的python服务器作为RHEL上的普通用户运行 但它需要在无法访问的地方创建文件/目录。 还需要使用随机UID/GID检查这些文件 我的方法 在仅限功能的环境中尝试此操作,无setuid。 我试图利用cap_chown和cap_dac_覆盖功能。 但是我完全不知道如何让它在systemctl这样的环境中工作 目前,我在服务文件中有以下内容: #cat /usr/lib/systemd/system/my_server.service [Service] Type=simple

我的要求

我的python服务器作为RHEL上的普通用户运行 但它需要在无法访问的地方创建文件/目录。 还需要使用随机UID/GID检查这些文件

我的方法

在仅限功能的环境中尝试此操作,无setuid。 我试图利用cap_chown和cap_dac_覆盖功能。 但是我完全不知道如何让它在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
但这里说的是,它永远不会在脚本上工作:

在当前设置下,我对正在运行的流程具有以下功能:

# 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模块使其工作吗?

setuid不能与脚本一起工作,因为它是一个安全漏洞,这是由于脚本的执行方式。这方面有几份文件。你甚至可以从查看维基百科页面开始


一个非常好的解决方法是编写一个小型C程序,该程序将使用到Python和脚本的硬编码路径启动Python脚本。关于所有问题的真正好的讨论可以在更新:

中找到这样做的方法,不确定是否是最好的方法。使用“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`

完成基于以上讨论,我做了以下工作:

[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;
  }
服务器执行以下操作来调用二进制文件

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

谢谢你的回复和链接。但我想我特别想避免脚本上的setuid,这就是为什么我想单独使用“Linux功能”。这就是我的问题,你现在是不是在用CAP_CHOWN运行你的整个服务器?是的,这是一个警告。但我认为我最初在.service文件等中设置功能的尝试也是在尝试在整个服务器上设置功能。您在评论中提到编写一个小型C程序,该程序将启动Python脚本,其中包含指向Python和脚本的硬编码路径。我不明白那部分。在你提到的链接中,我应该看哪一节来寻找一个例子?有一节开头是“这个问题的答案是使用setuid二进制文件来执行脚本”。但是如果你使用随机脚本chown功能,它所要做的就是修改和编辑/etc中的几个文件,然后,作为cron作业的一部分,它可以执行它想要的任何操作。您希望为您的chown创建一个新用户,并且希望它非常孤立。例如,请参阅。根据您拥有的linux版本,您可以直接向用户提供功能。但是您当然可以将您想要的功能添加到小型C程序允许的和可继承的功能中。如果您可以在小型C程序中完成所有需要的操作,那么您可能不需要SETUID。如果你需要从程序中调用一个脚本,你当然应该把它和C程序放在单独的用户控制下,从而隔离脚本。在可执行文件上使用setcap程序。
# 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