[Toybox] unshare/nsenter on centos 6.6.

Rob Landley rob at landley.net
Wed Sep 28 13:18:16 PDT 2016


I have a report that toybox won't build under centos 6.6 because
unshare() and nsenter() exist in linux/sched.h but not in libc.so. While
I can fix this with basically:

@@ -63,9 +64,11 @@ config NSENTER

 #define FOR_nsenter
 #include "toys.h"
+#include <sys/syscall.h>
 #include <linux/sched.h>
-int unshare(int flags);
-int setns(int fd, int nstype);
+
+#define unshare(flags) syscall(SYS_unshare, flags)
+#define setns(fd, nstype) syscall(SYS_setns, fd, nstype)

 GLOBALS(

I'm unsure what the right approach is here?

There's a compile-time probe checking to see if unshare() exists in the
headers, but I'm using linux/sched.h instead of sched.h because the
unshare(2) man page says:

   Feature Test Macro Requirements for glibc (see
   feature_test_macros(7)):

       unshare():
           Since glibc 2.14:
               _GNU_SOURCE
           Before glibc 2.14:
               _BSD_SOURCE || _SVID_SOURCE
                   /* _GNU_SOURCE also suffices */

I.E. they used to expose unshare() by default when you #included
<sched.h>, then they decided to break existing code, and that unshare
hadn't been created by Linux but had instead been created by The Hurd.
Or possibly they were declaring this new kernel syscall to be a
glibc-specific extension and refusing to wrap it by default? I don't
know, either way this is INSANE and I'm not going along with it. So I
included the linux header to get the function definition, but trusted
libc's system call wrappers to still be there 9because that's not
related to which headers you #included. Yes, they care hugely about
namespace pollution on your #includes, but the functions are still there
in libc. Jazzhands!)

So centos has a kernel with the system call, but their libc isn't
wrapping the system call. Except... the probe I wrote is not just
compiling but linking (in scripts/genconfig.sh the probesymbol
TOYBOX_CONTAINER call does not have -c after it, meaning gcc will
attempt to compile _and_ link the result, and report failure if it
couldn't link the binary either.)

I THINK what the reporter was hitting (don't currently have a centos
test system) is setns() not being there. Because the probe was testing
for unshare() but not setns(), and the command uses both. So this whole
"do I trust the libc wrapper functions to be there when I know they
broke their headers for crazy political reasons, or do I just do the
syscall() myself" is a side issue. It sounds like there was a kernel
version that had unshare() but not setns(), and centos fell in that hole
and provides a strange broken build environment in the name of "stability".

Yeah, the unshare system call was added in 2006, nsenter in 2010. So the
fix isn't to change toys/other/nsenter.c, but to add setns() to the
probe and say "nope, centos can't do this command" when the probe fails
due to the 6+ year old kernel. (If I did the syscall myself, it wouldn't
have the SYS_setns in sys/syscall.h anyway...)

That said... is it worse to prototype the wrapper functions myself, or
to make the syscall myself? (It's one of those "six of one" things where
I'm not really happy with either answer...)

Rob



More information about the Toybox mailing list