From 5707a64d9462001f9c7c2e02d3f52cf8b0181658 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sat, 31 Dec 2016 18:51:07 +0100 Subject: [PATCH] support: Helper functions for entering namespaces --- ChangeLog | 12 ++++ support/Makefile | 4 ++ support/namespace.h | 53 ++++++++++++++++ support/support_become_root.c | 40 ++++++++++++ support/support_enter_network_namespace.c | 74 +++++++++++++++++++++++ support/tst-support-namespace.c | 34 +++++++++++ support/xsocket.c | 36 +++++++++++ support/xsocket.h | 27 +++++++++ 8 files changed, 280 insertions(+) create mode 100644 support/namespace.h create mode 100644 support/support_become_root.c create mode 100644 support/support_enter_network_namespace.c create mode 100644 support/tst-support-namespace.c create mode 100644 support/xsocket.c create mode 100644 support/xsocket.h diff --git a/ChangeLog b/ChangeLog index 9685fde488e..e7b2fa130be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2016-12-31 Florian Weimer + + * 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. + 2016-12-31 Florian Weimer [BZ #17252] diff --git a/support/Makefile b/support/Makefile index 4e9d42ef096..9544a085738 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 \ ifeq ($(run-built-tests),yes) diff --git a/support/namespace.h b/support/namespace.h new file mode 100644 index 00000000000..4692907676a --- /dev/null +++ b/support/namespace.h @@ -0,0 +1,53 @@ +/* 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 + . */ + +#ifndef SUPPORT_NAMESPACE_H +#define SUPPORT_NAMESPACE_H + +#include +#include + +__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. + + Note that this function generally has to be called before a process + becomes multi-threaded, otherwise it may fail with insufficient + privileges on systems which would support this operation for + single-threaded processes. */ +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 00000000000..d13954c4dd4 --- /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 + . */ + +#include + +#include +#include +#include + +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 00000000000..3af18e6f5df --- /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 + . */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 00000000000..bd2a2a62e84 --- /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 + . */ + +#include +#include + +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 diff --git a/support/xsocket.c b/support/xsocket.c new file mode 100644 index 00000000000..9ebe63fc735 --- /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 + . */ + +#include + +#include +#include +#include + +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 00000000000..e9ff49e54ef --- /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 + . */ + +#ifndef SUPPORT_XSOCKET_H +#define SUPPORT_XSOCKET_H + +#include +#include + +int xsocket (int, int, int); + +#endif /* SUPPORT_XSOCKET_H */ -- 2.39.5