+++ date = "2023-03-28T23:59:00+08:00" draft = false tags = [] title = "Set Up a Test Harness with Mount Namespace" authors = ["xry111"] +++
I unintentionally introduced GCC PR109293 when I was fixing PR91085.
The issue is trivial to fix, but I wanted to test it in an environment where
memmem()
is indeed unavailable. However it's not easy to find one (the
PR mentions MinGW but I've never succeeded to build GCC on MinGW).
Yes, as a LFS editor I can hack Glibc code to hide memmem()
from the API
and ABI and build a system without it. But this approach seems too
overkill. But I'm also an OJ developer (who spends a large amount of time
attempting to hide things from the contestants :) so I soon came up with an
idea.
memmem()
from string.h
It's easy: just comment memmem()
out.
Then we need to inject string.h
into /usr/include
. We can just back theoriginal one up and install the modified header there, but this is obviously
dangerous and will be unacceptable in a real productive environment. So we
can create a new mount namespace and bind mount the header instead:
$ unshare -m -r
# mount --bind ~/no-memmem/string.h /usr/include/string.h
Note that to use a separate mount namespace (-m
), a separate user
namespace is also needed (-r
) and the current user will be mapped as
root
in the new user namespace. The bind mount is isolated in the
separate namespace, so it won't affect any applications running on the
system, but the programs started by the shell spawned by unshare
.
memmem()
from libc.so
It's not so easy. Initially I tried:
# objcopy /usr/lib/libc.so.6 -N memmem libc.so.6
# mount --bind libc.so.6 /usr/lib/libc.so.6
in the separate namespace. But it did not work. The objcopy
command
stripped memmem()
from the .symtab
section, so memmem()
did not show
up in objdump -t
output; however it was still in .dynsym
section, so it
still showed up in objdump -T
and it's enough for the linker to find the
symbol from a shared library.
So I created a no-memmem.a
file with:
# cat no-memmem.c
extern void __dont_use_memmem_no_exist();
void memmem(void) { __dont_use_memmem_no_exist(); }
# cc no-memmem.c -c
# ar cr no-memmem.a no-memmem.o
If we add no-memmem.a
into the gcc
command, anything using memmem
will fail to link like:
/usr/bin/ld: no-memmem.a(no-memmem.o): in function `memmem':
no-memmem.c:(.text+0xa): undefined reference to `__dont_use_memmem_no_exist'
Then how to inject no-memmem.a
for everything using libc.so
? Well,
libc.so
is a linker script:
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /usr/lib/ld-linux-x86-64.so.2 ) )
So we just need to copy libc.so
, adding the path to no-memmem.a
before
/usr/lib/libc.so.6
into the copy, and bind mount the copy onto
/usr/lib/libc.so
.
fixincl
succeeded to link in the namespace with memmem()
hidden, and
the memmem()
implementation in libiberty
is linked into the fixincl
executable as expected. Now the patch is OK to go!