Commit add40469 authored by Colin Walters's avatar Colin Walters

Drop -newnet variant

This was just a hack which worked around a RHEL6 kernel bug.  I no
longer care about RHEL6; linux-user-chroot is now just RHEL7 only.
parent 9e8f2ee9
......@@ -25,12 +25,6 @@ linux_user_chroot_SOURCES = \
linux_user_chroot_CFLAGS = $(AM_CFLAGS) $(LIBSECCOMP_CFLAGS)
linux_user_chroot_LDFLAGS = $(LIBSECCOMP_LIBS)
bin_PROGRAMS += linux-user-chroot-newnet
linux_user_chroot_newnet_SOURCES = src/linux-user-chroot-newnet.c
linux_user_chroot_newnet_CFLAGS = $(AM_CFLAGS)
newnet helper
This is an optional helper program that simply allows calling
CLONE_NEWNET and executing a child process. The reason this program
exists as an option is because on some Linux kernel configurations
(e.g. with the netfilter kernel module loaded), it's expensive to
create new network namespaces, and it may actually fail.
linux-user-chroot is intended to create namespaces quite dynamically,
but this conflicts somewhat with the goals of the developers who
contributed the functionality for typically more static "containers".
If you don't need this helper as a workaround, don't build it.
This helper program does NOT restrict further execution of setuid
binaries. Otherwise, you couldn't run linux-user-chroot inside of it,
and that would defeat the point.
However I don't believe the attack surface exposed by making an empty
network namespace is very high - it does mean that e.g. one could make
"sudo" fail to look up the username if it's configured to use LDAP.
But most setuid programs *should* be carefully checking errors
To enable building this helper, pass --enable-newnet-helper to
$ linux-user-chroot-newnet curl
curl: (6) Could not resolve host:; Unknown error
$ linux-user-chroot-newnet /bin/bash
$ # you're now in a shell without networking
......@@ -34,12 +34,6 @@ AC_ARG_ENABLE(documentation,
AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes)
[build newnet helper (see README.newnet)]),,
AM_CONDITIONAL(BUILD_NEWNET_HELPER, test x$enable_newnet_helper = xyes)
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil -*-
* newnet-suid: Allow allocating a new empty network namespace as
* non-root. This program is just a workaround for the kernel
* requiring large-order allocations (e.g. 4 pages) per network
* namespace.
* Copyright 2012 Colin Walters <>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sched.h>
static void fatal (const char *message, ...) __attribute__ ((noreturn)) __attribute__ ((format (printf, 1, 2)));
static void fatal_errno (const char *message) __attribute__ ((noreturn));
static void
fatal (const char *fmt,
va_list args;
va_start (args, fmt);
vfprintf (stderr, fmt, args);
putc ('\n', stderr);
va_end (args);
exit (1);
static void
fatal_errno (const char *message)
perror (message);
exit (1);
main (int argc,
char **argv)
const char *program;
uid_t ruid, euid, suid;
gid_t rgid, egid, sgid;
char **program_argv;
int child_status = 0;
pid_t child;
if (argc <= 0)
return 1;
if (argc < 1)
fatal ("PROGRAM [ARGS]... Run PROGRAM in an isolated network namespace");
program = argv[0];
program_argv = argv;
if (getresgid (&rgid, &egid, &sgid) < 0)
fatal_errno ("getresgid");
if (getresuid (&ruid, &euid, &suid) < 0)
fatal_errno ("getresuid");
if (rgid == 0)
rgid = ruid;
if ((child = syscall (__NR_clone, SIGCHLD | CLONE_NEWNET, NULL)) < 0)
perror ("clone");
if (child == 0)
/* Switch back to the uid of our invoking process. These calls are
* irrevocable - see setuid(2) */
if (setgid (rgid) < 0)
fatal_errno ("setgid");
if (setuid (ruid) < 0)
fatal_errno ("setuid");
if (execvp (program, program_argv) < 0)
fatal_errno ("execv");
/* Let's also setuid back in the parent - there's no reason to stay uid 0, and
* it's just better to drop privileges. */
if (setgid (rgid) < 0)
fatal_errno ("setgid");
if (setuid (ruid) < 0)
fatal_errno ("setuid");
/* Kind of lame to sit around blocked in waitpid, but oh well. */
if (waitpid (child, &child_status, 0) < 0)
fatal_errno ("waitpid");
if (WIFEXITED (child_status))
return WEXITSTATUS (child_status);
return 1;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment