mirror of
https://github.com/dynup/kpatch
synced 2025-02-04 11:11:31 +00:00
Merge pull request #398 from flaming-toast/patch-reenable
re-enable forced patch modules
This commit is contained in:
commit
c21cc1292f
@ -810,12 +810,16 @@ int kpatch_register(struct kpatch_module *kpmod, bool replace)
|
||||
|
||||
down(&kpatch_mutex);
|
||||
|
||||
kpmod->enabled = false;
|
||||
if (kpmod->enabled) {
|
||||
ret = -EINVAL;
|
||||
goto err_up;
|
||||
}
|
||||
|
||||
list_add_tail(&kpmod->list, &kpmod_list);
|
||||
|
||||
if (!try_module_get(kpmod->mod)) {
|
||||
ret = -ENODEV;
|
||||
goto err_up;
|
||||
goto err_list;
|
||||
}
|
||||
|
||||
list_for_each_entry(object, &kpmod->objects, list) {
|
||||
@ -931,8 +935,9 @@ err_unlink:
|
||||
if (kpatch_object_linked(object))
|
||||
kpatch_unlink_object(object);
|
||||
module_put(kpmod->mod);
|
||||
err_up:
|
||||
err_list:
|
||||
list_del(&kpmod->list);
|
||||
err_up:
|
||||
up(&kpatch_mutex);
|
||||
return ret;
|
||||
}
|
||||
@ -944,11 +949,13 @@ int kpatch_unregister(struct kpatch_module *kpmod)
|
||||
struct kpatch_func *func;
|
||||
int ret, force = 0;
|
||||
|
||||
if (!kpmod->enabled)
|
||||
return -EINVAL;
|
||||
|
||||
down(&kpatch_mutex);
|
||||
|
||||
if (!kpmod->enabled) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
do_for_each_linked_func(kpmod, func) {
|
||||
func->op = KPATCH_OP_UNPATCH;
|
||||
if (func->force)
|
||||
|
@ -35,6 +35,7 @@ extern struct kpatch_patch_dynrela __kpatch_dynrelas[], __kpatch_dynrelas_end[];
|
||||
extern struct kpatch_patch_hook __kpatch_hooks_load[], __kpatch_hooks_load_end[];
|
||||
extern struct kpatch_patch_hook __kpatch_hooks_unload[], __kpatch_hooks_unload_end[];
|
||||
extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[];
|
||||
extern char __kpatch_checksum[];
|
||||
|
||||
static struct kpatch_module kpmod;
|
||||
static struct kobject *patch_kobj;
|
||||
@ -60,29 +61,43 @@ static ssize_t patch_enabled_store(struct kobject *kobj,
|
||||
int ret;
|
||||
unsigned long val;
|
||||
|
||||
/* only disabling is supported */
|
||||
if (!kpmod.enabled)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = !!val;
|
||||
|
||||
/* only disabling is supported */
|
||||
if (val)
|
||||
return -EINVAL;
|
||||
ret = kpatch_register(&kpmod, replace);
|
||||
else
|
||||
ret = kpatch_unregister(&kpmod);
|
||||
|
||||
ret = kpatch_unregister(&kpmod);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t checksum_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", __kpatch_checksum);
|
||||
}
|
||||
|
||||
static struct kobj_attribute patch_enabled_attr =
|
||||
__ATTR(enabled, 0644, patch_enabled_show, patch_enabled_store);
|
||||
static struct kobj_attribute checksum_attr =
|
||||
__ATTR(checksum, 0444, checksum_show, NULL);
|
||||
|
||||
static struct attribute *kpatch_attrs[] = {
|
||||
&patch_enabled_attr.attr,
|
||||
&checksum_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group kpatch_attr_group = {
|
||||
.attrs = kpatch_attrs,
|
||||
};
|
||||
|
||||
static ssize_t func_old_addr_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
@ -356,14 +371,10 @@ static int __init patch_init(void)
|
||||
if (!patch_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sysfs_create_file(patch_kobj, &patch_enabled_attr.attr);
|
||||
if (ret)
|
||||
goto err_patch;
|
||||
|
||||
functions_kobj = kobject_create_and_add("functions", patch_kobj);
|
||||
if (!functions_kobj) {
|
||||
ret = -ENOMEM;
|
||||
goto err_sysfs;
|
||||
goto err_patch;
|
||||
}
|
||||
|
||||
kpmod.mod = THIS_MODULE;
|
||||
@ -385,13 +396,17 @@ static int __init patch_init(void)
|
||||
if (ret)
|
||||
goto err_objects;
|
||||
|
||||
ret = sysfs_create_group(patch_kobj, &kpatch_attr_group);
|
||||
if (ret)
|
||||
goto err_sysfs;
|
||||
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
kpatch_unregister(&kpmod);
|
||||
err_objects:
|
||||
patch_free_objects();
|
||||
kobject_put(functions_kobj);
|
||||
err_sysfs:
|
||||
sysfs_remove_file(patch_kobj, &patch_enabled_attr.attr);
|
||||
err_patch:
|
||||
kobject_put(patch_kobj);
|
||||
return ret;
|
||||
@ -403,7 +418,7 @@ static void __exit patch_exit(void)
|
||||
|
||||
patch_free_objects();
|
||||
kobject_put(functions_kobj);
|
||||
sysfs_remove_file(patch_kobj, &patch_enabled_attr.attr);
|
||||
sysfs_remove_group(patch_kobj, &kpatch_attr_group);
|
||||
kobject_put(patch_kobj);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ __kpatch_funcs = ADDR(.kpatch.funcs);
|
||||
__kpatch_funcs_end = ADDR(.kpatch.funcs) + SIZEOF(.kpatch.funcs);
|
||||
__kpatch_dynrelas = ADDR(.kpatch.dynrelas);
|
||||
__kpatch_dynrelas_end = ADDR(.kpatch.dynrelas) + SIZEOF(.kpatch.dynrelas);
|
||||
__kpatch_checksum = ADDR(.kpatch.checksum);
|
||||
SECTIONS
|
||||
{
|
||||
.kpatch.hooks.load : {
|
||||
|
@ -476,6 +476,9 @@ cd "$SRCDIR"
|
||||
make prepare >> "$LOGFILE" 2>&1 || die
|
||||
cd "$TEMPDIR/output"
|
||||
ld -r -o ../patch/output.o $(find . -name "*.o") >> "$LOGFILE" 2>&1 || die
|
||||
md5sum ../patch/output.o | awk '{printf "%s\0", $1}' > checksum.tmp || die
|
||||
objcopy --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly ../patch/output.o || die
|
||||
rm -f checksum.tmp
|
||||
cd "$TEMPDIR/patch"
|
||||
KPATCH_BUILD="$SRCDIR" KPATCH_NAME="$PATCHNAME" KBUILD_EXTRA_SYMBOLS="$SYMVERSFILE" make "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
|
||||
|
||||
|
@ -121,6 +121,21 @@ core_module_loaded () {
|
||||
grep -q "T kpatch_register" /proc/kallsyms
|
||||
}
|
||||
|
||||
get_module_name () {
|
||||
echo $(readelf -p .gnu.linkonce.this_module $1 | grep '\[.*\]' | awk '{print $3}')
|
||||
}
|
||||
|
||||
verify_module_checksum () {
|
||||
modname=$(get_module_name $1)
|
||||
[[ -z $modname ]] && return 1
|
||||
|
||||
checksum=$(readelf -p .kpatch.checksum $1 | grep '\[.*\]' | awk '{print $3}')
|
||||
[[ -z $checksum ]] && return 1
|
||||
|
||||
sysfs_checksum=$(cat /sys/kernel/kpatch/patches/${modname}/checksum)
|
||||
[[ $checksum == $sysfs_checksum ]] || return 1
|
||||
}
|
||||
|
||||
load_module () {
|
||||
if ! core_module_loaded; then
|
||||
if modprobe -q kpatch; then
|
||||
@ -131,6 +146,23 @@ load_module () {
|
||||
insmod "$COREMOD" || die "failed to load core module"
|
||||
fi
|
||||
fi
|
||||
|
||||
modname=$(get_module_name $1)
|
||||
moddir=/sys/kernel/kpatch/patches/$modname
|
||||
if [[ -d $moddir ]] ; then
|
||||
if [[ $(cat "${moddir}/enabled") -eq 0 ]]; then
|
||||
if verify_module_checksum $1; then # same checksum
|
||||
echo "module already loaded, re-enabling"
|
||||
echo 1 > ${moddir}/enabled || die "failed to re-enable module $modname"
|
||||
return
|
||||
else
|
||||
die "error: cannot re-enable patch module $modname, cannot verify checksum match"
|
||||
fi
|
||||
else
|
||||
die "error: module named $modname already loaded and enabled"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "loading patch module: $1"
|
||||
insmod "$1" "$2"
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ make || exit 1
|
||||
cd ../../kmod/patch || exit 1
|
||||
make clean || exit 1
|
||||
cp ../../test/testmod/output.o . || exit 1
|
||||
md5sum output.o | awk '{printf "%s\0", $1}' > checksum.tmp || exit 1
|
||||
objcopy --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly output.o || exit 1
|
||||
rm -f checksum.tmp
|
||||
KBUILD_EXTRA_SYMBOLS="$(readlink -e ../../kmod/core/Module.symvers)" make || exit 1
|
||||
cd ../../test/testmod
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user