|
@@ -0,0 +1,94 @@
|
|
|
|
++++
|
|
|
|
+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.
|
|
|
|
+
|
|
|
|
+[PR109293]: https://gcc.gnu.org/PR109293
|
|
|
|
+[PR91085]: https://gcc.gnu.org/PR91085
|
|
|
|
+
|
|
|
|
+## Hide `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:
|
|
|
|
+
|
|
|
|
+```text
|
|
|
|
+$ 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`.
|
|
|
|
+
|
|
|
|
+## Hide `memmem()` from `libc.so`
|
|
|
|
+
|
|
|
|
+It's not so easy. Initially I tried:
|
|
|
|
+
|
|
|
|
+```text
|
|
|
|
+# 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:
|
|
|
|
+
|
|
|
|
+```text
|
|
|
|
+/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:
|
|
|
|
+
|
|
|
|
+```text
|
|
|
|
+/* 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`.
|
|
|
|
+
|
|
|
|
+## Test result
|
|
|
|
+
|
|
|
|
+`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!
|