Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clone process support in python

Tags:

python

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

like image 233
Jorge E. Cardona Avatar asked Nov 14 '12 05:11

Jorge E. Cardona


People also ask

Which of the following statement is used to clone the python list?

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.


2 Answers

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.

like image 51
Jorge E. Cardona Avatar answered Oct 22 '22 21:10

Jorge E. Cardona


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.

like image 21
mkj Avatar answered Oct 22 '22 21:10

mkj