Testing on hosts with firewalls

Message ID f803d43d-2564-f689-1da1-e2b7671c344e@redhat.com
State New
Headers show

Commit Message

Florian Weimer Dec. 30, 2016, 11:56 a.m.
On 12/30/2016 11:51 AM, Andreas Schwab wrote:
> On Dez 30 2016, Florian Weimer <fweimer@redhat.com> wrote:

>

>> If this is a current upstream kernel with user namespaces enabled, I would

>> be worried, though.

>

> $ zgrep USER_NS /proc/config.gz

> CONFIG_USER_NS=y

> $ uname -r

> 4.9.0-2.g6fbc0c0-default


Hmm.  It turns out that the UID/GID mapping is not required.  Using 
Mike's ioctls, I could bring up the loopback interface within an 
unmodified user namespace (created by an unprivileged user).

I'm now testing the attached patch.  It should use network namespaces 
even on kernels which lack user namespace support, as long as the tests 
are run as root.

Thanks,
Florian

Patch hide | download patch | download mbox

support: Helper functions for entering namespaces

2016-12-30  Florian Weimer  <fweimer@redhat.com>

	* support/namespace.h: New file.
	* support/support_become_root.c: Likewise.
	* support/support_enter_network_namespace.c: Likewise.
	* support/tst-support-namespace.c: Likewise.
	* support/xsocket.c: Likewise.
	* support/xsocket.h: Likewise.
	* support/Makefile (libsupport-routines): Add support_become_root,
	support_enter_network_namespace, xsocket.
	(tests): Add tst-support-namespace.

diff --git a/support/Makefile b/support/Makefile
index 1bde8bd..8e3b89d 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -30,6 +30,8 @@  libsupport-routines = \
   ignore_stderr \
   oom_error \
   set_fortify_handler \
+  support_become_root \
+  support_enter_network_namespace \
   support_record_failure \
   support_test_main \
   support_test_verify_impl \
@@ -54,6 +56,7 @@  libsupport-routines = \
   xpthread_spin_lock \
   xpthread_spin_unlock \
   xrealloc \
+  xsocket \
   xwaitpid \
 
 libsupport-static-only-routines := $(libsupport-routines)
@@ -65,6 +68,7 @@  endif
 
 tests = \
   README-testing \
+  tst-support-namespace \
   tst-support_record_failure \
 
 tests-special = \
diff --git a/support/namespace.h b/support/namespace.h
new file mode 100644
index 0000000..ba0229f
--- /dev/null
+++ b/support/namespace.h
@@ -0,0 +1,48 @@ 
+/* Entering namespaces for test case isolation.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_NAMESPACE_H
+#define SUPPORT_NAMESPACE_H
+
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Attempts to become root (or acquire root-like privileges), possibly
+   with the help of user namespaces.  Return true if (restricted) root
+   privileges could be attained in some way.  Print diagnostics to
+   standard output.  */
+bool support_become_root (void);
+
+/* Enter a network namespace (and a UTS namespace if possible) and
+   configure the loopback interface.  Return true if a network
+   namespace could be created.  Print diagnostics to standard output.
+   If a network namespace could be created, but networking in it could
+   not be configured, terminate the process.  It is recommended to
+   call support_become_root before this function so that the process
+   has sufficient privileges.  */
+bool support_enter_network_namespace (void);
+
+/* Return true if support_enter_network_namespace managed to enter a
+   UTS namespace.  */
+bool support_in_uts_namespace (void);
+
+__END_DECLS
+
+#endif
diff --git a/support/support_become_root.c b/support/support_become_root.c
new file mode 100644
index 0000000..d13954c
--- /dev/null
+++ b/support/support_become_root.c
@@ -0,0 +1,40 @@ 
+/* Acquire root privileges.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/namespace.h>
+
+#include <sched.h>
+#include <stdio.h>
+#include <unistd.h>
+
+bool
+support_become_root (void)
+{
+#ifdef CLONE_NEWUSER
+  if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0)
+    /* Even if we do not have UID zero, we have extended privileges at
+       this point.  */
+    return true;
+#endif
+  if (setuid (0) != 0)
+    {
+      printf ("warning: could not become root outside namespace (%m)\n");
+      return false;
+    }
+  return true;
+}
diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c
new file mode 100644
index 0000000..3af18e6
--- /dev/null
+++ b/support/support_enter_network_namespace.c
@@ -0,0 +1,74 @@ 
+/* Enter a network namespace.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/namespace.h>
+
+#include <net/if.h>
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <xsocket.h>
+
+static bool in_uts_namespace;
+
+bool
+support_enter_network_namespace (void)
+{
+#ifdef CLONE_NEWUTS
+  if (unshare (CLONE_NEWUTS) == 0)
+    in_uts_namespace = true;
+  else
+    printf ("warning: unshare (CLONE_NEWUTS) failed: %m\n");
+#endif
+
+#ifdef CLONE_NEWNET
+  if (unshare (CLONE_NEWNET) == 0)
+    {
+      /* Bring up the loopback interface.  */
+      int fd = xsocket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+      struct ifreq req;
+      strcpy (req.ifr_name, "lo");
+      TEST_VERIFY_EXIT (ioctl (fd, SIOCGIFFLAGS, &req) == 0);
+      bool already_up = req.ifr_flags & IFF_UP;
+      if (already_up)
+        /* This means that we likely have not achieved isolation from
+           the parent namespace.  */
+        printf ("warning: loopback interface already exists"
+                " in new network namespace\n");
+      else
+        {
+          req.ifr_flags |= IFF_UP | IFF_RUNNING;
+          TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
+        }
+      close (fd);
+
+      return !already_up;
+    }
+#endif
+  printf ("warning: could not enter network namespace\n");
+  return false;
+}
+
+bool
+support_in_uts_namespace (void)
+{
+  return in_uts_namespace;
+}
diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c
new file mode 100644
index 0000000..bd2a2a6
--- /dev/null
+++ b/support/tst-support-namespace.c
@@ -0,0 +1,34 @@ 
+/* Test entering namespaces.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <support/namespace.h>
+
+static int
+do_test (void)
+{
+  if (support_become_root ())
+    printf ("info: acquired root-like privileges\n");
+  if (support_enter_network_namespace ())
+    printf ("info: entered network namespace\n");
+  if (support_in_uts_namespace ())
+    printf ("info: also entered UTS namespace\n");
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/xsocket.c b/support/xsocket.c
new file mode 100644
index 0000000..9ebe63f
--- /dev/null
+++ b/support/xsocket.c
@@ -0,0 +1,36 @@ 
+/* socket with error checking.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xsocket (int domain, int type, int protocol)
+{
+  int fd = socket (domain, type, protocol);
+  if (fd < 0)
+    {
+      support_record_failure ();
+      printf ("error: socket (%d, %d, %d): %m\n", domain, type, protocol);
+      exit (1);
+    }
+  return fd;
+}
diff --git a/support/xsocket.h b/support/xsocket.h
new file mode 100644
index 0000000..e9ff49e
--- /dev/null
+++ b/support/xsocket.h
@@ -0,0 +1,27 @@ 
+/* Error-checking wrappers for socket functions.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_XSOCKET_H
+#define SUPPORT_XSOCKET_H
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+int xsocket (int, int, int);
+
+#endif /* SUPPORT_XSOCKET_H */