Beispiel #1
0
def simple_unshare(mount=True,
                   uts=True,
                   ipc=True,
                   net=False,
                   pid=False,
                   user=False,
                   hostname=None):
    """Simpler helper for setting up namespaces quickly.

    If support for any namespace type is not available, we'll silently skip it.

    Args:
        mount: Create a mount namespace.
        uts: Create a UTS namespace.
        ipc: Create an IPC namespace.
        net: Create a net namespace.
        pid: Create a pid namespace.
        user: Create a user namespace.
        hostname: hostname to use for the UTS namespace
    """
    # user namespace must be first
    if user and os.getuid() != 0:
        create_userns()

    # The mount namespace is the only one really guaranteed to exist --
    # it's been supported forever and it cannot be turned off.
    if mount:
        unshare(CLONE_NEWNS)

        # Avoid mounts in the new namespace from affecting the parent namespace
        # on systems that share the rootfs by default, but allow events in the
        # parent to propagate down.
        try:
            _mount(None, '/', None, MS_REC | MS_SLAVE)
        except OSError as e:
            if e.errno != errno.EINVAL:
                raise

    if uts:
        create_utsns(hostname)

    # The IPC namespace was added 2.6.19 and may be disabled in the kernel.
    if ipc:
        try:
            unshare(CLONE_NEWIPC)
        except OSError as e:
            if e.errno != errno.EINVAL:
                pass

    if net:
        create_netns()

    if pid:
        create_pidns()
Beispiel #2
0
def simple_unshare(mount=True, uts=True, ipc=True, net=False, pid=False,
                   user=False, hostname=None):
    """Simpler helper for setting up namespaces quickly.

    If support for any namespace type is not available, we'll silently skip it.

    Args:
        mount: Create a mount namespace.
        uts: Create a UTS namespace.
        ipc: Create an IPC namespace.
        net: Create a net namespace.
        pid: Create a pid namespace.
        user: Create a user namespace.
        hostname: hostname to use for the UTS namespace
    """
    # user namespace must be first
    if user and os.getuid() != 0:
        create_userns()

    # The mount namespace is the only one really guaranteed to exist --
    # it's been supported forever and it cannot be turned off.
    if mount:
        unshare(CLONE_NEWNS)

        # Avoid mounts in the new namespace from affecting the parent namespace
        # on systems that share the rootfs by default, but allow events in the
        # parent to propagate down.
        try:
            _mount(None, '/', None, MS_REC | MS_SLAVE)
        except OSError as e:
            if e.errno != errno.EINVAL:
                raise

    if uts:
        create_utsns(hostname)

    # The IPC namespace was added 2.6.19 and may be disabled in the kernel.
    if ipc:
        try:
            unshare(CLONE_NEWIPC)
        except OSError as e:
            if e.errno != errno.EINVAL:
                pass

    if net:
        create_netns()

    if pid:
        create_pidns()
Beispiel #3
0
def create_pidns():
    """Start a new pid namespace

    This will launch all the right manager processes.  The child that returns
    will be isolated in a new pid namespace.

    If functionality is not available, then it will return w/out doing anything.

    Returns:
        The last pid outside of the namespace.
    """
    first_pid = os.getpid()

    try:
        # First create the namespace.
        unshare(CLONE_NEWPID)
    except OSError as e:
        if e.errno == errno.EINVAL:
            # For older kernels, or the functionality is disabled in the config,
            # return silently.  We don't want to hard require this stuff.
            return first_pid
        else:
            # For all other errors, abort.  They shouldn't happen.
            raise

    # Now that we're in the new pid namespace, fork.  The parent is the master
    # of it in the original namespace, so it only monitors the child inside it.
    # It is only allowed to fork once too.
    pid = os.fork()
    if pid:
        # Mask SIGINT with the assumption that the child will catch & process it.
        # We'll pass that back up below.
        signal.signal(signal.SIGINT, signal.SIG_IGN)

        # Forward the control of the terminal to the child so it can manage input.
        _safe_tcsetpgrp(sys.stdin.fileno(), pid)

        # Reap the children as the parent of the new namespace.
        exit_as_status(_reap_children(pid))
    else:
        # Make sure to unshare the existing mount point if needed.  Some distros
        # create shared mount points everywhere by default.
        try:
            _mount(None, '/proc', 'proc', MS_PRIVATE | MS_REC)
        except OSError as e:
            if e.errno != errno.EINVAL:
                raise

        # The child needs its own proc mount as it'll be different.
        _mount(
            'proc', '/proc', 'proc',
            MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME)

        pid = os.fork()
        if pid:
            # Mask SIGINT with the assumption that the child will catch & process it.
            # We'll pass that back up below.
            signal.signal(signal.SIGINT, signal.SIG_IGN)

            # Now that we're in a new pid namespace, start a new process group so that
            # children have something valid to use.  Otherwise getpgrp/etc... will get
            # back 0 which tends to confuse -- you can't setpgrp(0) for example.
            os.setpgrp()

            # Forward the control of the terminal to the child so it can manage input.
            _safe_tcsetpgrp(sys.stdin.fileno(), pid)

            # Watch all of the children.  We need to act as the master inside the
            # namespace and reap old processes.
            exit_as_status(_reap_children(pid))

    # Create a process group for the grandchild so it can manage things
    # independent of the init process.
    os.setpgrp()

    # The grandchild will return and take over the rest of the sdk steps.
    return first_pid
Beispiel #4
0
def create_pidns():
    """Start a new pid namespace

    This will launch all the right manager processes.  The child that returns
    will be isolated in a new pid namespace.

    If functionality is not available, then it will return w/out doing anything.

    Returns:
        The last pid outside of the namespace.
    """
    first_pid = os.getpid()

    try:
        # First create the namespace.
        unshare(CLONE_NEWPID)
    except OSError as e:
        if e.errno == errno.EINVAL:
            # For older kernels, or the functionality is disabled in the config,
            # return silently.  We don't want to hard require this stuff.
            return first_pid
        else:
            # For all other errors, abort.  They shouldn't happen.
            raise

    # Now that we're in the new pid namespace, fork.  The parent is the master
    # of it in the original namespace, so it only monitors the child inside it.
    # It is only allowed to fork once too.
    pid = os.fork()
    if pid:
        # Mask SIGINT with the assumption that the child will catch & process it.
        # We'll pass that back up below.
        signal.signal(signal.SIGINT, signal.SIG_IGN)

        # Forward the control of the terminal to the child so it can manage input.
        _safe_tcsetpgrp(sys.stdin.fileno(), pid)

        # Reap the children as the parent of the new namespace.
        exit_as_status(_reap_children(pid))
    else:
        # Make sure to unshare the existing mount point if needed.  Some distros
        # create shared mount points everywhere by default.
        try:
            _mount(None, '/proc', 'proc', MS_PRIVATE | MS_REC)
        except OSError as e:
            if e.errno != errno.EINVAL:
                raise

        # The child needs its own proc mount as it'll be different.
        _mount('proc', '/proc', 'proc',
               MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME)

        pid = os.fork()
        if pid:
            # Mask SIGINT with the assumption that the child will catch & process it.
            # We'll pass that back up below.
            signal.signal(signal.SIGINT, signal.SIG_IGN)

            # Now that we're in a new pid namespace, start a new process group so that
            # children have something valid to use.  Otherwise getpgrp/etc... will get
            # back 0 which tends to confuse -- you can't setpgrp(0) for example.
            os.setpgrp()

            # Forward the control of the terminal to the child so it can manage input.
            _safe_tcsetpgrp(sys.stdin.fileno(), pid)

            # Watch all of the children.  We need to act as the master inside the
            # namespace and reap old processes.
            exit_as_status(_reap_children(pid))

    # Create a process group for the grandchild so it can manage things
    # independent of the init process.
    os.setpgrp()

    # The grandchild will return and take over the rest of the sdk steps.
    return first_pid