Aoldguy
Aoldguy

Reputation: 11

Why Does User ID Remain 65534 When Using Clone to Create a New User Namespace in Python Script?

I am trying to create a new user namespace using a Python script that utilizes the clone system call. My goal is to map the user ID of a newly spawned shell to a specific value, similar to how it's done with the unshare command.

When I run unshare --user sh, I can successfully update the UID mappings via:

echo '0 502 1' > /proc/[PID]/uid_map
echo '0 502 1' > /proc/[PID]/gid_map

After doing this, running id in the new shell shows the user as root.

However, when I attempt to do the same in a Python script using libc.clone, the shell still reports the user ID as 65534 (nobody) even after updating the UID and GID mappings. Here is my script:

import signal
import os
import ctypes
import sys

CLONE_NEWUTS = 0x04000000
CLONE_NEWUSER = 0x10000000

def write_file(path, content):
    try:
        with open(path, "w") as f:
            f.write(content)
    except Exception as e:
        sys.exit(f"[Error] Failed to write mapping {content} to {path}: {e}")

def child_func():
    input("...>")
    os.execlp("bash", "sh")  # Start a new shell

libc = ctypes.CDLL("libc.so.6", use_errno=True)
STACK_SIZE = 1024 * 1024
stack = ctypes.create_string_buffer(STACK_SIZE)

child_stack = ctypes.c_void_p(ctypes.addressof(stack) + STACK_SIZE)
pid = libc.clone(
    ctypes.CFUNCTYPE(ctypes.c_int)(child_func),
    child_stack,
    CLONE_NEWUTS | CLONE_NEWUSER | signal.SIGCHLD,
)

if pid == -1:
    sys.exit("Failed to create new namespace")

print(pid)
write_file(f"/proc/{pid}/setgroups", "deny\n")
write_file(f"/proc/{pid}/uid_map", f"0 502 1\n")
write_file(f"/proc/{pid}/gid_map", f"0 502 1\n")

os.waitpid(pid, 0)

What I have checked:

Despite these steps, the user inside the namespace remains nobody. What might I be missing? Any advice or insights would be appreciated.

Upvotes: 1

Views: 31

Answers (1)

Swati
Swati

Reputation: 124

The issue you're encountering lies in the timing of when the uid_map and gid_map are written in relation to the child process and its execution within the new user namespace. In your script, the mapping files are written after the clone system call is made, which means the new child process isn't aware of those mappings at the time it starts.

To solve this issue, the uid_map and gid_map should be written before the child process is executed inside the new user namespace. This ensures that the mappings are already set up by the time the child process is started.

Upvotes: 0

Related Questions