The klp-build script prepares a clean patch by populating two temporary
directories ('a' and 'b') with source files and diffing the result.
However, this process currently fails when a patch introduces a new
source file as the script attempts to copy files that do not yet exist
in the original source tree.

Update the file-copying logic in refresh_patch() to verify existence
before processing:

- Filter the files list to ensure only files currently present in $SRC
  are copied to the 'a' directory.
- Apply the patch, then verify file existence again before copying
  to the 'b' directory.
- Ignore "/dev/null" entries, which represent non-existent files in
  patch headers.

This allows klp-build to successfully process patches that add new
source files to the kernel.

Signed-off-by: Joe Lawrence <[email protected]>
---
 scripts/livepatch/klp-build | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

This problem was found with a simple patch that included a new header
file:

  diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c
  index a6f76121955f..d1927ad00bb3 100644
  --- a/fs/proc/cmdline.c
  +++ b/fs/proc/cmdline.c
  @@ -4,11 +4,11 @@
   #include <linux/proc_fs.h>
   #include <linux/seq_file.h>
   #include "internal.h"
  +#include "test.h"
   
   static int cmdline_proc_show(struct seq_file *m, void *v)
   {
  -       seq_puts(m, saved_command_line);
  -       seq_putc(m, '\n');
  +       seq_printf(m, test_string, saved_command_line);
          return 0;
   }
   
  diff --git a/fs/proc/test.h b/fs/proc/test.h
  new file mode 100644
  index 000000000000..94de7114cf86
  --- /dev/null
  +++ b/fs/proc/test.h
  @@ -0,0 +1 @@
  +#define test_string "%s klp=1\n"

And the build failure:

  $ ./scripts/livepatch/klp-build /tmp/new-file-test.patch
  Validating patch(es)
  error: dev/null: does not exist and --remove not passed
  fatal: Unable to process path dev/null
  error: klp-build: line 315: 'git update-index -q --refresh -- "${files[@]}"'
  error: klp-build: line 316: '( cd "$SRC"; git update-index -q --refresh -- 
"${files[@]}" )'
  error: fs/proc/test.h: No such file or directory
  error: patch failed: fs/proc/cmdline.c:4
  error: fs/proc/cmdline.c: patch does not apply
  error: klp-build: line 366: 'git apply --reverse "${extra_args[@]}"'
  error: klp-build: line 367: 'echo "error: $SCRIPT: $*" 1>&2'

While I don't think the script needs to handle a patch that is trying to
add completely new compilation units (that would require Makefile
changes, generate new .o files, etc.), I do think it would be helpful to
at least support patches that add new header/included files.  For
example, a common klp-macros.h file may be helpful to mimic the old
kpatch-build kpatch-macros.h, collect shadow variable IDs, etc.

diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 964f9ed5ee1b..5a8c592c4c15 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -426,6 +426,8 @@ refresh_patch() {
        local patch="$1"
        local tmpdir="$PATCH_TMP_DIR"
        local files=()
+       local orig_files=()
+       local patched_files=()
 
        rm -rf "$tmpdir"
        mkdir -p "$tmpdir/a"
@@ -434,12 +436,20 @@ refresh_patch() {
        # Get all source files affected by the patch
        get_patch_files "$patch" | mapfile -t files
 
-       # Copy orig source files to 'a'
-       ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents 
--target-directory="$tmpdir/a" )
+       # Copy orig source files to 'a', filter to only existing files
+       for file in "${files[@]}"; do
+               [[ "$file" != "dev/null" ]] && [[ -f "$SRC/$file" ]] && 
orig_files+=("$file")
+       done
+       ( cd "$SRC" && echo "${orig_files[@]}" | xargs cp --parents 
--target-directory="$tmpdir/a" )
 
-       # Copy patched source files to 'b'
+       # Copy patched source files to 'b', filter to only existing
+       # files after patch application
        apply_patch "$patch" --recount
-       ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents 
--target-directory="$tmpdir/b" )
+       for file in "${files[@]}"; do
+               [[ "$file" != "dev/null" ]] && [[ -f "$SRC/$file" ]] && 
patched_files+=("$file")
+       done
+       ( cd "$SRC" && echo "${patched_files[@]}" | xargs cp --parents 
--target-directory="$tmpdir/b" )
+
        revert_patch "$patch" --recount
 
        # Diff 'a' and 'b' to make a clean patch
-- 
2.52.0


Reply via email to