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.
@@ -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 = \
new file mode 100644
@@ -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
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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>
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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 */