Skip to content

Commit

Permalink
Merge pull request #1130 from joe-lawrence/hook-hacking-helpers
Browse files Browse the repository at this point in the history
Hook hacking helpers
  • Loading branch information
sm00th authored Oct 13, 2021
2 parents 03893f6 + f5175a4 commit 912c2cb
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 8 deletions.
5 changes: 4 additions & 1 deletion kmod/patch/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ KPATCH_BUILD ?= /lib/modules/$(shell uname -r)/build
KPATCH_MAKE = $(MAKE) -C $(KPATCH_BUILD) M=$(PWD) CFLAGS_MODULE='$(CFLAGS_MODULE)'
LDFLAGS += $(KPATCH_LDFLAGS)

# object files that this Makefile can (re)build on its own
BUILDABLE_OBJS=$(filter-out output.o, $(wildcard *.o))

obj-m += $(KPATCH_NAME).o
ldflags-y += -T $(src)/kpatch.lds
targets += kpatch.lds
Expand All @@ -19,5 +22,5 @@ patch-hook.o: patch-hook.c kpatch-patch-hook.c livepatch-patch-hook.c
$(KPATCH_MAKE) patch-hook.o

clean:
$(RM) -Rf .*.o.cmd .*.ko.cmd .tmp_versions *.o *.ko *.mod.c \
$(RM) -Rf .*.o.cmd .*.ko.cmd .tmp_versions $(BUILDABLE_OBJS) *.ko *.mod.c \
Module.symvers
106 changes: 106 additions & 0 deletions kmod/patch/livepatch-patch-hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,28 @@
* done, the scaffold structs are no longer needed.
*/

/*
* lpatch is the kernel data structure that will be created on patch
* init, registered with the livepatch API on init, and finally
* unregistered when the patch exits. Its struct klp_object *objs
* member must be dynamically allocated according to the number of
* target objects it will be patching.
*/
static struct klp_patch *lpatch;

static LIST_HEAD(patch_objects);
static int patch_objects_nr;

/**
* struct patch_object - scaffolding structure tracking patch target objects
* @list: list of patch_object (threaded onto patch_objects)
* @funcs: list of patch_func associated with this object
* @relocs: list of patch_reloc associated with this object
* @callbacks: kernel struct of object callbacks
* @name: patch target object name (NULL for vmlinux)
* @funcs_nr: count of kpatch_patch_func added to @funcs
* @relocs_nr: count of patch_reloc added to @relocs
*/
struct patch_object {
struct list_head list;
struct list_head funcs;
Expand All @@ -119,16 +137,36 @@ struct patch_object {
int funcs_nr, relocs_nr;
};

/**
* struct patch_func - scaffolding structure for kpatch_patch_func
* @list: list of patch_func (threaded onto patch_object.funcs)
* @kfunc: array of kpatch_patch_func
*/
struct patch_func {
struct list_head list;
struct kpatch_patch_func *kfunc;
};

/**
* struct patch_reloc - scaffolding structure for kpatch_patch_dynrela
* @list: list of patch_reloc (threaded onto patch_object.relocs)
* @kdynrela: array of kpatch_patch_dynrela
*/
struct patch_reloc {
struct list_head list;
struct kpatch_patch_dynrela *kdynrela;
};

/**
* patch_alloc_new_object() - creates and initializes a new patch_object
* @name: target object name
*
* Return: pointer to new patch_object, NULL on failure.
*
* Does not check for previously created patch_objects with the same
* name. Updates patch_objects_nr and threads new data structure onto
* the patch_objects list.
*/
static struct patch_object *patch_alloc_new_object(const char *name)
{
struct patch_object *object;
Expand All @@ -147,6 +185,16 @@ static struct patch_object *patch_alloc_new_object(const char *name)
return object;
}

/**
* patch_find_object_by_name() - find or create a patch_object with a
* given name
* @name: target object name
*
* Return: pointer to patch_object, NULL on failure.
*
* Searches the patch_objects list for an already created instance with
* @name, otherwise tries to create it via patch_alloc_new_object()
*/
static struct patch_object *patch_find_object_by_name(const char *name)
{
struct patch_object *object;
Expand All @@ -158,6 +206,17 @@ static struct patch_object *patch_find_object_by_name(const char *name)
return patch_alloc_new_object(name);
}

/**
* patch_add_func_to_object() - create scaffolding from kpatch_patch_func data
*
* @kfunc: Individual kpatch_patch_func pointer
*
* Return: 0 on success, -ENOMEM on failure.
*
* Builds scaffolding data structures from .kpatch.funcs section's array
* of kpatch_patch_func structures. Updates the associated
* patch_object's funcs_nr count.
*/
static int patch_add_func_to_object(struct kpatch_patch_func *kfunc)
{
struct patch_func *func;
Expand All @@ -180,6 +239,17 @@ static int patch_add_func_to_object(struct kpatch_patch_func *kfunc)
}

#ifndef HAVE_ELF_RELOCS
/**
* patch_add_reloc_to_object() - create scaffolding from kpatch_patch_dynrela data
*
* @kdynrela: Individual kpatch_patch_dynrela pointer
*
* Return: 0 on success, -ENOMEM on failure.
*
* Builds scaffolding data structures from .kpatch.dynrelas section's array
* of kpatch_patch_dynrela structures. Updates the associated
* patch_object's relocs_nr count.
*/
static int patch_add_reloc_to_object(struct kpatch_patch_dynrela *kdynrela)
{
struct patch_reloc *reloc;
Expand All @@ -202,6 +272,9 @@ static int patch_add_reloc_to_object(struct kpatch_patch_dynrela *kdynrela)
}
#endif

/**
* patch_free_scaffold() - tear down the temporary kpatch scaffolding
*/
static void patch_free_scaffold(void) {
struct patch_func *func, *safefunc;
struct patch_object *object, *safeobject;
Expand All @@ -227,6 +300,9 @@ static void patch_free_scaffold(void) {
}
}

/**
* patch_free_livepatch() - release the klp_patch and friends
*/
static void patch_free_livepatch(struct klp_patch *patch)
{
struct klp_object *object;
Expand All @@ -246,12 +322,21 @@ static void patch_free_livepatch(struct klp_patch *patch)
}
}

/* Defined by kpatch.lds.S */
extern struct kpatch_pre_patch_callback __kpatch_callbacks_pre_patch[], __kpatch_callbacks_pre_patch_end[];
extern struct kpatch_post_patch_callback __kpatch_callbacks_post_patch[], __kpatch_callbacks_post_patch_end[];
extern struct kpatch_pre_unpatch_callback __kpatch_callbacks_pre_unpatch[], __kpatch_callbacks_pre_unpatch_end[];
extern struct kpatch_post_unpatch_callback __kpatch_callbacks_post_unpatch[], __kpatch_callbacks_post_unpatch_end[];

#ifdef HAVE_CALLBACKS
/**
* add_callbacks_to_patch_objects() - create patch_objects that have callbacks
*
* Return: 0 on success, -ENOMEM or -EINVAL on failure
*
* Iterates through all kpatch pre/post-(un)patch callback data
* structures and creates scaffolding patch_objects for them.
*/
static int add_callbacks_to_patch_objects(void)
{
struct kpatch_pre_patch_callback *p_pre_patch_callback;
Expand Down Expand Up @@ -341,6 +426,7 @@ static inline int add_callbacks_to_patch_objects(void)
}
#endif /* HAVE_CALLBACKS */

/* Defined by kpatch.lds.S */
extern struct kpatch_patch_func __kpatch_funcs[], __kpatch_funcs_end[];
#ifndef HAVE_ELF_RELOCS
extern struct kpatch_patch_dynrela __kpatch_dynrelas[], __kpatch_dynrelas_end[];
Expand All @@ -360,6 +446,12 @@ static int __init patch_init(void)
struct klp_reloc *lrelocs, *lreloc;
#endif


/*
* Step 1 - read from output.o, create temporary scaffolding
* data-structures
*/

/* organize functions and relocs by object in scaffold */
for (kfunc = __kpatch_funcs;
kfunc != __kpatch_funcs_end;
Expand All @@ -386,6 +478,16 @@ static int __init patch_init(void)
/* past this point, only possible return code is -ENOMEM */
ret = -ENOMEM;

/*
* Step 2 - create livepatch klp_patch and friends
*
* There are two dynamically allocated parts:
*
* klp_patch
* klp_object objs [patch_objects_nr] <= i
* klp_func funcs [object->funcs_nr] <= j
*/

/* allocate and fill livepatch structures */
lpatch = kzalloc(sizeof(*lpatch), GFP_KERNEL);
if (!lpatch)
Expand Down Expand Up @@ -456,6 +558,10 @@ static int __init patch_init(void)
i++;
}

/*
* Step 3 - throw away scaffolding
*/

/*
* Once the patch structure that the live patching API expects
* has been built, we can release the scaffold structure.
Expand Down
24 changes: 17 additions & 7 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ SRCDIR="$CACHEDIR/src"
RPMTOPDIR="$CACHEDIR/buildroot"
VERSIONFILE="$CACHEDIR/version"
TEMPDIR="$CACHEDIR/tmp"
ENVFILE="$TEMPDIR/kpatch-build.env"
LOGFILE="$CACHEDIR/build.log"
RELEASE_FILE=/etc/os-release
DEBUG=0
Expand Down Expand Up @@ -89,6 +90,10 @@ logger() {
fi
}

save_env() {
export -p | grep -wv -e 'OLDPWD=' -e 'PWD=' > "$ENVFILE"
}

verify_patch_files() {
local path
local dir
Expand Down Expand Up @@ -432,6 +437,7 @@ find_special_section_data() {
[[ -z "$PRINTK_INDEX_STRUCT_SIZE" && "$CONFIG_PRINTK_INDEX" -ne 0 ]] && die "can't find special struct pi_entry size"
[[ -z "$STATIC_CALL_STRUCT_SIZE" ]] && kernel_version_gte 5.10.0 && die "can't find special struct static_call_site size"

save_env
return
}

Expand Down Expand Up @@ -714,6 +720,7 @@ elif [[ "$DISTRO" = ubuntu ]] || [[ "$DISTRO" = debian ]]; then

export PATH="/usr/lib/ccache:$PATH"
fi
save_env

find_dirs || die "can't find supporting tools"

Expand Down Expand Up @@ -927,6 +934,7 @@ find_special_section_data
if [[ $DEBUG -ge 4 ]]; then
export KPATCH_GCC_DEBUG=1
fi
save_env

echo "Building original source"
[[ -n "$OOT_MODULE" ]] || ./scripts/setlocalversion --save-scmversion || die
Expand Down Expand Up @@ -959,10 +967,9 @@ cp -f "$SRCDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die
echo "Building patched source"
apply_patches
mkdir -p "$TEMPDIR/orig" "$TEMPDIR/patched"
KPATCH_GCC_TEMPDIR="$TEMPDIR"
export KPATCH_GCC_TEMPDIR
KPATCH_GCC_SRCDIR="$SRCDIR"
export KPATCH_GCC_SRCDIR
export KPATCH_GCC_TEMPDIR="$TEMPDIR"
export KPATCH_GCC_SRCDIR="$SRCDIR"
save_env
# $TARGETS used as list, no quotes.
# shellcheck disable=SC2086
KBUILD_MODPOST_WARN=1 make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die
Expand Down Expand Up @@ -1123,6 +1130,7 @@ export KCFLAGS="-I$DATADIR/patch $ARCH_KCFLAGS"
if [[ "$USE_KLP" -eq 0 ]]; then
export KCPPFLAGS="-D__KPATCH_MODULE__"
fi
save_env

echo "Building patch module: $MODNAME.ko"

Expand Down Expand Up @@ -1164,10 +1172,12 @@ for ((idx=0; idx<${#MAKEVARS[@]}; idx++)); do
MAKEVARS[$idx]=${MAKEVARS[$idx]/${KPATCH_CC_PREFIX}/}
done

KPATCH_BUILD="$KPATCH_BUILD" KPATCH_NAME="$MODNAME" \
export KPATCH_BUILD="$KPATCH_BUILD" KPATCH_NAME="$MODNAME" \
KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \
KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \
make "${MAKEVARS[@]}" 2>&1 | logger || die
KPATCH_LDFLAGS="$KPATCH_LDFLAGS"
save_env

make "${MAKEVARS[@]}" 2>&1 | logger || die

if [[ "$USE_KLP" -eq 1 ]]; then
if [[ "$USE_KLP_ARCH" -eq 0 ]]; then
Expand Down

0 comments on commit 912c2cb

Please sign in to comment.