Is there any support of the syscall clone(2)
(not os.fork
) in Python? I want to play with Linux namespaces under Python but it seems that there is not a lot of information about it.
Edits:
I think ctypes with libc is the answer but I'm still not having any success. fork works without problems since it doesn't have any argument then this code work:
from ctypes import *
libc = CDLL("libc.so.6")
libc.fork()
With clone I'm trying this:
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()
Clone actually has this signature:
int clone(int (*fn)(void *), void *child_stack, int flags, void arg, ... / pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
I still need to pass *child_stack and flags but have no idea how to do it. Any help?
More Edits:
I got this now:
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)
This actually works but I imagine I making a big hole in my system with the stack, there is a cleaner way to do this?
Edits:
Almost done, adding the correct flag for 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)
This is not runnable just for root, and print a nice 1.
And following this post the stack seems to be fine: http://code.google.com/p/chromium/wiki/LinuxPidNamespaceSupport
3. List copy using =(assignment operator) This is the simplest method of cloning a list by using = operators. This operator assigns the old list to the new list using Python = operators.
Well, finally I think I got the answer, is just usign ctypes with libc,
This is a simple proof of concept:
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)
This has to be run by root.
If you want to have "fork() but with new namespace" semantics, you can directly call the SYS_clone
syscall instead. Note that if you do so, the os.getpid()
method will return the wrong process ID in the child because glibc caches the process ID and doesn't know about the SYS_clone
invocation to invalidate its cache.
Assuming x86_64 (NR_clone == 56
, NR_getpid == 39
), you can call libc.syscall(56, signal.SIGCHLD|0x000200000, 0 0 0)
to "fork", and then libc.syscall(39)
to get the current PID of the "forked" child process.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With