我的python程序需要提升权限,因此由root(使用setuid-binary-wrapper)启动。
为了尽可能减少攻击面(以及编码错误的影响),我决定将我的代码分成两部分:一部分将作为root
执行,另一部分将执行regular user
权限。问题是,代码是相互依赖的,因此需要secure two-way communication
。
我不知道这是否是正确的方法(欢迎其他想法),但我决定使用two processes
- 一个具有提升权限的父进程和一个具有常规权限的子进程用户
想法:
问题:
subprocess
(。Popen)是否足够? multiprocessing
会更适合吗?
子进程和父进程如何以交互式安全方式进行通信(subprocess.PIPE
是否安全)?
您知道这种情况下的任何简单代码示例吗?
根据Gil Hamilton的建议,我想出了以下代码
仍有一些问题:
os.setuid(<unprivileged UID>)
是否足够? privileged.py
:
#!/bin/python
from multiprocessing import Process, Pipe
from unprivileged import Unprivileged
if __name__ == '__main__':
privilegedProcessPipeEnd, unprivilegedProcessPipeEnd = Pipe()
unprivilegedProcess = Process(target=Unprivileged(unprivilegedProcessPipeEnd).operate)
unprivilegedProcess.start()
print(privilegedProcessPipeEnd.recv())
privilegedProcessPipeEnd.send("ok")
print(privilegedProcessPipeEnd.recv())
privilegedProcessPipeEnd.send("nok")
privilegedProcessPipeEnd.close()
unprivilegedProcessPipeEnd.close()
unprivilegedProcess.join()
unprivileged.py
:
import os
class Unprivileged:
def __init__(self, unprivilegedProcessPipeEnd):
self._unprivilegedProcessPipeEnd = unprivilegedProcessPipeEnd
def operate(self):
invokerUid = os.getuid()
if invokerUid == 0:
# started by root; TODO: drop to predefined standard user
# os.setuid(standardUid)
pass
else:
# started by a regular user through a setuid-binary
os.setuid(invokerUid) # TODO: drop to predefined standard user (save invokerUid for future stuff)
# os.setuid(0) # not permitted anymore, cannot become root again
print("os.getuid(): " + str(os.getuid()))
self._unprivilegedProcessPipeEnd.send("invoke privilegedFunction1")
print(self._unprivilegedProcessPipeEnd.recv())
self._unprivilegedProcessPipeEnd.send("invoke privilegedFunction2")
print(self._unprivilegedProcessPipeEnd.recv())
return
main.c
(setuid-wrapper program):
#include <unistd.h>
#define SCRIPT_PATH "/home/u1/project/src/privileged.py"
int
main(int argc,
char **argv) {
return execv(SCRIPT_PATH, argv);
}
/* compile and run like this:
$ gcc -std=c99 main.c -o main
# chown root:root main
# chmod 6771 main
$ chmod +x /home/u1/project/src/privileged.py
$ ./main
*/
答案 0 :(得分:1)
这可以通过Popen
完成,但它有点笨拙的IMO,因为您无法控制Popen
的流程转换。如果您依靠UID来减弱权限,则需要fork
,然后在子项中调整您的UID,然后再调用其他子代码。
(没有正当理由你不能将你的子代码放在你用Popen
调用的单独程序中并让它调整其UID作为第一步,它在我看来只是一种奇怪的方式来构造它。)
我建议您查看使用multiprocessing
模块。该模块可以轻松创建一个新进程(它将为您处理fork)。然后,您可以轻松地放入调整UID的代码(见下文),然后您可以在相同的“代码库”中运行子代码。也就是说,您不一定需要来调用单独的程序。
multiprocessing
模块还提供了自己的Pipe
对象以及Queue
对象,这两个对象都是进程间通信机制。两者都是安全的 - 在某种意义上说,没有外部用户可以加入它们(没有root权限)。但是,当然如果您的非特权子进程受到损害,它可以将任何想要的内容发送给父进程,这样您的特权父进程仍然需要验证/审核其输入。
multiprocessing
模块的文档提供了几个简单的示例,可以帮助您入门。创建后,使用管道就像读取和写入文件一样简单。
至于调整UID,在调用您想要作为非特权用户运行的代码之前,这只是对子进程中os.setuid
的单个调用。有关详细信息,请阅读setuid(2)
和credentials(7)
手册页。