Files
Joe Lawrence 45b3b9b162 objtool/klp: Introduce klp diff subcommand for diffing object files
JIRA: https://issues.redhat.com/browse/RHEL-114916

commit dd590d4d57ebeeb826823c288741f2ed20f452af
Author: Josh Poimboeuf <jpoimboe@kernel.org>
Date:   Wed Sep 17 09:03:59 2025 -0700

    objtool/klp: Introduce klp diff subcommand for diffing object files

    Add a new klp diff subcommand which performs a binary diff between two
    object files and extracts changed functions into a new object which can
    then be linked into a livepatch module.

    This builds on concepts from the longstanding out-of-tree kpatch [1]
    project which began in 2012 and has been used for many years to generate
    livepatch modules for production kernels.  However, this is a complete
    rewrite which incorporates hard-earned lessons from 12+ years of
    maintaining kpatch.

    Key improvements compared to kpatch-build:

      - Integrated with objtool: Leverages objtool's existing control-flow
        graph analysis to help detect changed functions.

      - Works on vmlinux.o: Supports late-linked objects, making it
        compatible with LTO, IBT, and similar.

      - Simplified code base: ~3k fewer lines of code.

      - Upstream: No more out-of-tree #ifdef hacks, far less cruft.

      - Cleaner internals: Vastly simplified logic for symbol/section/reloc
        inclusion and special section extraction.

      - Robust __LINE__ macro handling: Avoids false positive binary diffs
        caused by the __LINE__ macro by introducing a fix-patch-lines script
        (coming in a later patch) which injects #line directives into the
        source .patch to preserve the original line numbers at compile time.

    Note the end result of this subcommand is not yet functionally complete.
    Livepatch needs some ELF magic which linkers don't like:

      - Two relocation sections (.rela*, .klp.rela*) for the same text
        section.

      - Use of SHN_LIVEPATCH to mark livepatch symbols.

    Unfortunately linkers tend to mangle such things.  To work around that,
    klp diff generates a linker-compliant intermediate binary which encodes
    the relevant KLP section/reloc/symbol metadata.

    After module linking, a klp post-link step (coming soon) will clean up
    the mess and convert the linked .ko into a fully compliant livepatch
    module.

    Note this subcommand requires the diffed binaries to have been compiled
    with -ffunction-sections and -fdata-sections, and processed with
    'objtool --checksum'.  Those constraints will be handled by a klp-build
    script introduced in a later patch.

    Without '-ffunction-sections -fdata-sections', reliable object diffing
    would be infeasible due to toolchain limitations:

      - For intra-file+intra-section references, the compiler might
        occasionally generated hard-coded instruction offsets instead of
        relocations.

      - Section-symbol-based references can be ambiguous:

        - Overlapping or zero-length symbols create ambiguity as to which
          symbol is being referenced.

        - A reference to the end of a symbol (e.g., checking array bounds)
          can be misinterpreted as a reference to the next symbol, or vice
          versa.

    A potential future alternative to '-ffunction-sections -fdata-sections'
    would be to introduce a toolchain option that forces symbol-based
    (non-section) relocations.

    Acked-by: Petr Mladek <pmladek@suse.com>
    Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
    Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
2026-01-07 12:55:01 -05:00

77 lines
2.5 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* External livepatch interfaces for patch creation tooling
*/
#ifndef _LINUX_LIVEPATCH_EXTERNAL_H_
#define _LINUX_LIVEPATCH_EXTERNAL_H_
#include <linux/types.h>
#define KLP_RELOC_SEC_PREFIX ".klp.rela."
#define KLP_SYM_PREFIX ".klp.sym."
#define __KLP_PRE_PATCH_PREFIX __klp_pre_patch_callback_
#define __KLP_POST_PATCH_PREFIX __klp_post_patch_callback_
#define __KLP_PRE_UNPATCH_PREFIX __klp_pre_unpatch_callback_
#define __KLP_POST_UNPATCH_PREFIX __klp_post_unpatch_callback_
#define KLP_PRE_PATCH_PREFIX __stringify(__KLP_PRE_PATCH_PREFIX)
#define KLP_POST_PATCH_PREFIX __stringify(__KLP_POST_PATCH_PREFIX)
#define KLP_PRE_UNPATCH_PREFIX __stringify(__KLP_PRE_UNPATCH_PREFIX)
#define KLP_POST_UNPATCH_PREFIX __stringify(__KLP_POST_UNPATCH_PREFIX)
struct klp_object;
typedef int (*klp_pre_patch_t)(struct klp_object *obj);
typedef void (*klp_post_patch_t)(struct klp_object *obj);
typedef void (*klp_pre_unpatch_t)(struct klp_object *obj);
typedef void (*klp_post_unpatch_t)(struct klp_object *obj);
/**
* struct klp_callbacks - pre/post live-(un)patch callback structure
* @pre_patch: executed before code patching
* @post_patch: executed after code patching
* @pre_unpatch: executed before code unpatching
* @post_unpatch: executed after code unpatching
* @post_unpatch_enabled: flag indicating if post-unpatch callback
* should run
*
* All callbacks are optional. Only the pre-patch callback, if provided,
* will be unconditionally executed. If the parent klp_object fails to
* patch for any reason, including a non-zero error status returned from
* the pre-patch callback, no further callbacks will be executed.
*/
struct klp_callbacks {
klp_pre_patch_t pre_patch;
klp_post_patch_t post_patch;
klp_pre_unpatch_t pre_unpatch;
klp_post_unpatch_t post_unpatch;
bool post_unpatch_enabled;
};
/*
* 'struct klp_{func,object}_ext' are compact "external" representations of
* 'struct klp_{func,object}'. They are used by objtool for livepatch
* generation. The structs are then read by the livepatch module and converted
* to the real structs before calling klp_enable_patch().
*
* TODO make these the official API for klp_enable_patch(). That should
* simplify livepatch's interface as well as its data structure lifetime
* management.
*/
struct klp_func_ext {
const char *old_name;
void *new_func;
unsigned long sympos;
};
struct klp_object_ext {
const char *name;
struct klp_func_ext *funcs;
struct klp_callbacks callbacks;
unsigned int nr_funcs;
};
#endif /* _LINUX_LIVEPATCH_EXTERNAL_H_ */