klp-build's elf_create_file() fails with EINVAL when the build directory
path is long enough to truncate the "XXXXXX" suffix in the 256-byte
tmp_name buffer. Increase the buffer to PATH_MAX and add a truncation
check to ensure a valid template string for mkstemp().

Signed-off-by: Joe Lawrence <[email protected]>
---
 tools/objtool/elf.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

Repro notes:

  # Consider a looooong path like:
  $ 
LONG_DIR=tests/gitlab.com/joe.lawrence/kernel-tests/-/archive/klp-build/kernel-tests-klp-build.tar.gz/general/kpatch/patch-upgrade/kpatch/kernel/BUILD/kernel-6.12.0-178.1964_2250006255.el10/linux-6.12.0-178.1964_2250006255.el10.x86_64

  # Place the source repo within the long path
  $ mkdir -p /tmp/"$LONG_DIR"
  $ cd /tmp/"$LONG_DIR"
  $ git clone --depth=1 --branch=v6.19-rc4 
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  $ cd linux

  # Grab a sample patch
  $ wget 
https://raw.githubusercontent.com/dynup/kpatch/refs/heads/master/examples/cmdline-string.patch

  # Basic config for livepatching ...
  $ make -j$(nproc) defconfig
  $ ./scripts/config --file .config \
      --set-val CONFIG_FTRACE y \
      --set-val CONFIG_KALLSYMS_ALL y \
      --set-val CONFIG_FUNCTION_TRACER y \
      --set-val CONFIG_DYNAMIC_FTRACE y \
      --set-val CONFIG_DYNAMIC_DEBUG y \
      --set-val CONFIG_LIVEPATCH y
  $ make olddefconfig

  # BAD BUILD, mkstemp() unhappy:
  $ ./scripts/livepatch/klp-build -T cmdline-string.patch
  Validating patch(es)
  Building original kernel
  Copying original object files
  Fixing patch(es)
  Building patched kernel
  Copying patched object files
  Diffing objects
  vmlinux.o: changed function: cmdline_proc_show
  vmlinux.o: error: objtool [elf.c:1233]: elf_create_file: can't create tmp 
file failed: Invalid argument
  error: klp-build: objtool klp diff failed
  error: klp-build: line 657: '( cd "$ORIG_DIR"; "${cmd[@]}" > >(tee -a "$log") 
2> >(tee -a "$log" | "${filter[@]}" 1>&2) || die "objtool klp diff failed" )'

  # GOOD BUILD, with PATH_MAX buffer for mkstemp():
  $ ./scripts/livepatch/klp-build -S 3 -T cmdline-string.patch
  Diffing objects
  vmlinux.o: changed function: cmdline_proc_show
  Building patch module: livepatch-cmdline-string.ko
  SUCCESS

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 2c02c7b49265..836575876741 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h>
 #include <errno.h>
 #include <libgen.h>
 #include <ctype.h>
@@ -1192,6 +1193,7 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char 
*name)
        char *dir, *base, *tmp_name;
        struct symbol *sym;
        struct elf *elf;
+       int path_len;
 
        elf_version(EV_CURRENT);
 
@@ -1219,13 +1221,17 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char 
*name)
 
        base = basename(base);
 
-       tmp_name = malloc(256);
+       tmp_name = malloc(PATH_MAX);
        if (!tmp_name) {
                ERROR_GLIBC("malloc");
                return NULL;
        }
 
-       snprintf(tmp_name, 256, "%s/%s.XXXXXX", dir, base);
+       path_len = snprintf(tmp_name, PATH_MAX, "%s/%s.XXXXXX", dir, base);
+       if (path_len >= PATH_MAX) {
+               ERROR_GLIBC("snprintf");
+               return NULL;
+       }
 
        elf->fd = mkstemp(tmp_name);
        if (elf->fd == -1) {
-- 
2.52.0


Reply via email to