fake-uname: fix gcc argument order and improve preloaded shared library
authorMichael Prokop <mika@grml.org>
Thu, 29 Apr 2021 22:25:44 +0000 (00:25 +0200)
committerMichael Prokop <mika@grml.org>
Fri, 30 Apr 2021 11:22:57 +0000 (13:22 +0200)
This includes recent changes as integrated at
https://github.com/sipwise/deployment-iso

Makefile:

- Fix gcc argument order: newer gcc versions have become more picky on
  their argument order, due to the --as-needed default, and require the
  libraries to be linked to, to be passed after the code/objects that
  use them, otherwise they will get dropped as unused. This change is
  required for compiling with gcc v10.2.1-6 as present on
  Debian/bullseye (otherwise fails to execute with `undefined symbol:
  dlsym`)
- Add `make check` target to run some basic tests
- Also get rid of *.o *.so files in clean target, adjust targets
  accordingly to always clean and then build fake-uname.so afterwards
- Mark as serial-only via .NOTPARALLEL

fake-uname.c:

- Use hidden visibility by default, and export the symbol explicitly.
- Resolve real_uname() only once.
- Return early if the real_uname() fails, to avoid acting on bogus data.
- Call dlerror() before dlsym() to clear any previous errors.
- Compute the release member size from the utsname struct instead of
  hard-coding it.
- Always NUL-terminate the relese buffer, so protect against very long
  environment strings.
- Make various variables into const.

Acked-by: Guillem Jover <gjover@sipwise.com>
Thanks: Guillem Jover

packer/Makefile
packer/fake-uname.c

index 6a94be0..9d60c35 100644 (file)
@@ -1,43 +1,57 @@
 GRML_DEBOOTSTRAP_VERSION=latest
 GRML_DEBOOTSTRAP_LOCAL_PATH=$(shell pwd)/local_dir
 
-compile: fake-uname.so
+CFLAGS ?= -ggdb -O2 -Wall -Wextra -Wno-unused-parameter
+CFLAGS += -fPIC -fvisibility=hidden
+LDLIBS ?=
+LDLIBS += -ldl
+
+PLUGIN = fake-uname.so
+
+$(PLUGIN): fake-uname.c
+       $(CC) $(CFLAGS) $(LDFLAGS) $< $(LDLIBS) -o $@ -shared
+
+UNAME_CHECK = LD_PRELOAD="$(CURDIR)/$(PLUGIN)" uname
+
+check: $(PLUGIN)
+       echo "$(UNAME_CHECK)"
+       test "0.0.0" = "$(shell $(UNAME_CHECK) -r)"
+       test "1.2.3" = "$(shell UTS_RELEASE="1.2.3" $(UNAME_CHECK) -r)"
 
 install:
        cd .. && make DESTDIR=packer/local_dir install
 
 clean:
+       $(RM) *.o *.so
        rm -rf local_dir
 
-fake-uname.so:
-       gcc -shared -fPIC -ldl fake-uname.c -o fake-uname.so
-
 # Debian 11
-bullseye: fake-uname.so clean install
+bullseye: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 10
-buster: fake-uname.so clean install
+buster: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 9
-stretch: fake-uname.so clean install
+stretch: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 8
-jessie: fake-uname.so clean install
+jessie: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 7
-wheezy: fake-uname.so clean install
+wheezy: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 6.0
-squeeze: fake-uname.so clean install
+squeeze: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 5.0
-lenny: fake-uname.so clean install
+lenny: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 .PHONY: compile bullseye buster stretch jessie wheezy squeeze lenny
+.NOTPARALLEL:
index 7bbcb24..d71a4f4 100644 (file)
 #define RTLD_NEXT      ((void *) -1l)
 #endif
 
-typedef int (*uname_t) (struct utsname * buf);
+#define SYMBOL_EXPORT __attribute__((visibility("default")))
+
+typedef int uname_func(struct utsname *buf);
 
 static void *get_libc_func(const char *funcname)
 {
   void *func;
   char *error;
 
+  /* Clear any previous errors. */
+  dlerror();
   func = dlsym(RTLD_NEXT, funcname);
-  if ((error = dlerror()) != NULL) {
-    fprintf(stderr, "Can't locate libc function `%s' error: %s", funcname, error);
+  error = dlerror();
+  if (error != NULL) {
+    fprintf(stderr, "Cannot locate libc function '%s' error: %s",
+            funcname, error);
     _exit(EXIT_FAILURE);
   }
   return func;
 }
 
-int uname(struct utsname *buf)
+int SYMBOL_EXPORT uname(struct utsname *buf)
 {
+  static uname_func *real_uname;
+  const char *release;
   int ret;
-  char *env = NULL;
-  uname_t real_uname = (uname_t) get_libc_func("uname");
 
-  ret = real_uname((struct utsname *) buf);
-  strncpy(buf->release, ((env = getenv("UTS_RELEASE")) == NULL) ? UTS_RELEASE : env, 65);
+  if (real_uname == NULL)
+    real_uname = (uname_func *)get_libc_func("uname");
+
+  ret = real_uname(buf);
+  if (ret < 0)
+    return ret;
+
+  release = getenv("UTS_RELEASE");
+  if (release == NULL)
+    release = UTS_RELEASE;
+  strncpy(buf->release, release, sizeof(buf->release) - 1);
+  buf->release[sizeof(buf->release) - 1] = '\0';
+
   return ret;
 }