12

Python中是否支持系统调用clone(2)not )? os.fork我想在 Python 下使用 Linux 命名空间,但似乎没有太多关于它的信息。

编辑:

我认为带有 libc 的 ctypes 是答案,但我仍然没有任何成功。fork 工作没有问题,因为它没有任何参数,然后这段代码工作:

from ctypes import *

libc = CDLL("libc.so.6")
libc.fork()

使用克隆我正在尝试这个:

from ctypes import *

def f():
    print "In callback."
    return 0

libc = CDLL("libc.so.6")

f_c = CFUNCTYPE(c_int)(f)

print libc.getpid()
print libc.clone(f_c)
print get_errno()

克隆实际上有这个签名:

int clone(int (*fn)(void *), void *child_stack, int flags, void arg, ... / pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

我仍然需要传递 *child_stack 和 flags 但不知道该怎么做。有什么帮助吗?

更多编辑:

我现在得到了这个:

from ctypes import *

def f():
    print "In callback."
    return 0

libc = CDLL("libc.so.6")

f_c = CFUNCTYPE(c_int)(f)
stack = c_char_p(" " * 1024 * 1024)
libc.clone(f_c, c_void_p(cast(stack, c_void_p).value + 1024 * 1024), 0)

这实际上可行,但我想我用堆栈在我的系统中打了一个大洞,有一种更清洁的方法可以做到这一点吗?

编辑:

几乎完成,为 newpid 添加正确的标志:

from ctypes import *

libc = CDLL("libc.so.6")

def f():
    print libc.getpid()
    return 0

f_c = CFUNCTYPE(c_int)(f)
stack = c_char_p(" " * 1024 * 1024)
libc.clone(f_c, c_void_p(cast(stack, c_void_p).value + 1024 * 1024), 0x20000000)

这不能仅针对 root 运行,并打印一个不错的 1。

在这篇文章之后,堆栈似乎很好:http ://code.google.com/p/chromium/wiki/LinuxPidNamespaceSupport

4

2 回答 2

9

好吧,最后我想我得到了答案,就是将ctypes与 libc 一起使用,

这是一个简单的概念证明:

from ctypes import *

libc = CDLL("libc.so.6")

# Create stack.                                                                                                                                                                            
stack = c_char_p(" " * 8096)

def f():
    print libc.getpid()
    return 0

# Conver function to c type returning an integer.                                                                                                                                          
f_c = CFUNCTYPE(c_int)(f)

# We need the top of the stack.                                                                                                                                                            
stack_top = c_void_p(cast(stack, c_void_p).value + 8096)

# Call clone with the NEWPID Flag                                                                                                                                                          
libc.clone(f_c, stack_top, 0x20000000)

这必须由 root 运行。

于 2012-11-14T07:34:27.067 回答
1

如果您想拥有“fork() 但具有新命名空间”语义,则可以直接调用SYS_clone系统调用。请注意,如果这样做,该os.getpid()方法将在子进程中返回错误的进程 ID,因为 glibc 缓存了进程 ID,并且不知道SYS_clone调用以使其缓存无效。

假设 x86_64 ( NR_clone == 56, NR_getpid == 39),您可以调用libc.syscall(56, signal.SIGCHLD|0x000200000, 0 0 0)“fork”,然后libc.syscall(39)获取“fork”子进程的当前 PID。

于 2013-05-08T01:58:52.407 回答