Blame SOURCES/0003-re-enable-patch-modules-with-checksum-matching.patch

576586
From b0058988c7e57627ae64ace40377de6da4fa14b9 Mon Sep 17 00:00:00 2001
576586
From: Jessica Yu <jyu@cowsay.org>
576586
Date: Thu, 4 Sep 2014 07:38:17 -0700
576586
Subject: [PATCH 3/3] re-enable patch modules with checksum matching
576586
To: rhkernel-list@redhat.com
576586
576586
In order to safely re-enable patch modules, add a special
576586
.kpatch.checksum section containing an md5sum of a patch module's
576586
contents. The contents of this section are exported to sysfs via
576586
patch_init and double checked when kpatch load finds that a module of
576586
the same name is already loaded.
576586
576586
Conflicts:
576586
	kpatch-build/kpatch-build
576586
---
576586
 kmod/core/core.c               | 19 ++++++++++++------
576586
 kmod/patch/kpatch-patch-hook.c | 45 ++++++++++++++++++++++++++++--------------
576586
 kmod/patch/kpatch.lds          |  1 +
576586
 kpatch-build/kpatch-build      |  5 ++++-
576586
 kpatch/kpatch                  | 32 ++++++++++++++++++++++++++++++
576586
 5 files changed, 80 insertions(+), 22 deletions(-)
576586
576586
diff --git a/kmod/core/core.c b/kmod/core/core.c
576586
index 8c1bb37..bb624a9 100644
576586
--- a/kmod/core/core.c
576586
+++ b/kmod/core/core.c
576586
@@ -811,12 +811,16 @@ int kpatch_register(struct kpatch_module *kpmod, bool replace)
576586
 
576586
 	down(&kpatch_mutex);
576586
 
576586
-	kpmod->enabled = false;
576586
+	if (kpmod->enabled) {
576586
+		ret = -EINVAL;
576586
+		goto err_up;
576586
+	}
576586
+
576586
 	list_add_tail(&kpmod->list, &kpmod_list);
576586
 
576586
 	if (!try_module_get(kpmod->mod)) {
576586
 		ret = -ENODEV;
576586
-		goto err_up;
576586
+		goto err_list;
576586
 	}
576586
 
576586
 	list_for_each_entry(object, &kpmod->objects, list) {
576586
@@ -932,8 +936,9 @@ err_unlink:
576586
 		if (kpatch_object_linked(object))
576586
 			kpatch_unlink_object(object);
576586
 	module_put(kpmod->mod);
576586
-err_up:
576586
+err_list:
576586
 	list_del(&kpmod->list);
576586
+err_up:
576586
 	up(&kpatch_mutex);
576586
 	return ret;
576586
 }
576586
@@ -945,11 +950,13 @@ int kpatch_unregister(struct kpatch_module *kpmod)
576586
 	struct kpatch_func *func;
576586
 	int ret, force = 0;
576586
 
576586
-	if (!kpmod->enabled)
576586
-		return -EINVAL;
576586
-
576586
 	down(&kpatch_mutex);
576586
 
576586
+	if (!kpmod->enabled) {
576586
+	    ret = -EINVAL;
576586
+	    goto out;
576586
+	}
576586
+
576586
 	do_for_each_linked_func(kpmod, func) {
576586
 		func->op = KPATCH_OP_UNPATCH;
576586
 		if (func->force)
576586
diff --git a/kmod/patch/kpatch-patch-hook.c b/kmod/patch/kpatch-patch-hook.c
576586
index ea68878..1370223 100644
576586
--- a/kmod/patch/kpatch-patch-hook.c
576586
+++ b/kmod/patch/kpatch-patch-hook.c
576586
@@ -35,6 +35,7 @@ extern struct kpatch_patch_dynrela __kpatch_dynrelas[], __kpatch_dynrelas_end[];
576586
 extern struct kpatch_patch_hook __kpatch_hooks_load[], __kpatch_hooks_load_end[];
576586
 extern struct kpatch_patch_hook __kpatch_hooks_unload[], __kpatch_hooks_unload_end[];
576586
 extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[];
576586
+extern char __kpatch_checksum[];
576586
 
576586
 static struct kpatch_module kpmod;
576586
 static struct kobject *patch_kobj;
576586
@@ -61,29 +62,43 @@ static ssize_t patch_enabled_store(struct kobject *kobj,
576586
 	int ret;
576586
 	unsigned long val;
576586
 
576586
-	/* only disabling is supported */
576586
-	if (!kpmod.enabled)
576586
-		return -EINVAL;
576586
-
576586
 	ret = kstrtoul(buf, 10, &val;;
576586
 	if (ret)
576586
 		return ret;
576586
 
576586
 	val = !!val;
576586
 
576586
-	/* only disabling is supported */
576586
 	if (val)
576586
-		return -EINVAL;
576586
+		ret = kpatch_register(&kpmod, replace);
576586
+	else
576586
+		ret = kpatch_unregister(&kpmod);
576586
 
576586
-	ret = kpatch_unregister(&kpmod);
576586
 	if (ret)
576586
 		return ret;
576586
 
576586
 	return count;
576586
 }
576586
 
576586
+static ssize_t checksum_show(struct kobject *kobj,
576586
+				  struct kobj_attribute *attr, char *buf)
576586
+{
576586
+	return snprintf(buf, PAGE_SIZE, "%s\n", __kpatch_checksum);
576586
+}
576586
+
576586
 static struct kobj_attribute patch_enabled_attr =
576586
 	__ATTR(enabled, 0644, patch_enabled_show, patch_enabled_store);
576586
+static struct kobj_attribute checksum_attr =
576586
+	__ATTR(checksum, 0444, checksum_show, NULL);
576586
+
576586
+static struct attribute *kpatch_attrs[] = {
576586
+	&patch_enabled_attr.attr,
576586
+	&checksum_attr.attr,
576586
+	NULL,
576586
+};
576586
+
576586
+static struct attribute_group kpatch_attr_group = {
576586
+	.attrs = kpatch_attrs,
576586
+};
576586
 
576586
 static ssize_t func_old_addr_show(struct kobject *kobj,
576586
 				  struct kobj_attribute *attr, char *buf)
576586
@@ -354,14 +369,10 @@ static int __init patch_init(void)
576586
 	if (!patch_kobj)
576586
 		return -ENOMEM;
576586
 
576586
-	ret = sysfs_create_file(patch_kobj, &patch_enabled_attr.attr);
576586
-	if (ret)
576586
-		goto err_patch;
576586
-
576586
 	functions_kobj = kobject_create_and_add("functions", patch_kobj);
576586
 	if (!functions_kobj) {
576586
 		ret = -ENOMEM;
576586
-		goto err_sysfs;
576586
+		goto err_patch;
576586
 	}
576586
 
576586
 	kpmod.mod = THIS_MODULE;
576586
@@ -383,13 +394,17 @@ static int __init patch_init(void)
576586
 	if (ret)
576586
 		goto err_objects;
576586
 
576586
+	ret = sysfs_create_group(patch_kobj, &kpatch_attr_group);
576586
+	if (ret)
576586
+		goto err_sysfs;
576586
+
576586
 	return 0;
576586
 
576586
+err_sysfs:
576586
+	kpatch_unregister(&kpmod);
576586
 err_objects:
576586
 	patch_free_objects();
576586
 	kobject_put(functions_kobj);
576586
-err_sysfs:
576586
-	sysfs_remove_file(patch_kobj, &patch_enabled_attr.attr);
576586
 err_patch:
576586
 	kobject_put(patch_kobj);
576586
 	return ret;
576586
@@ -401,7 +416,7 @@ static void __exit patch_exit(void)
576586
 
576586
 	patch_free_objects();
576586
 	kobject_put(functions_kobj);
576586
-	sysfs_remove_file(patch_kobj, &patch_enabled_attr.attr);
576586
+	sysfs_remove_group(patch_kobj, &kpatch_attr_group);
576586
 	kobject_put(patch_kobj);
576586
 }
576586
 
576586
diff --git a/kmod/patch/kpatch.lds b/kmod/patch/kpatch.lds
576586
index 105e5e6..49ae8e7 100644
576586
--- a/kmod/patch/kpatch.lds
576586
+++ b/kmod/patch/kpatch.lds
576586
@@ -2,6 +2,7 @@ __kpatch_funcs = ADDR(.kpatch.funcs);
576586
 __kpatch_funcs_end = ADDR(.kpatch.funcs) + SIZEOF(.kpatch.funcs);
576586
 __kpatch_dynrelas = ADDR(.kpatch.dynrelas);
576586
 __kpatch_dynrelas_end = ADDR(.kpatch.dynrelas) + SIZEOF(.kpatch.dynrelas);
576586
+__kpatch_checksum = ADDR(.kpatch.checksum);
576586
 SECTIONS
576586
 {
576586
   .kpatch.hooks.load : {
576586
diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build
576586
index 91bf5c2..38466f4 100755
576586
--- a/kpatch-build/kpatch-build
576586
+++ b/kpatch-build/kpatch-build
576586
@@ -343,7 +343,7 @@ else
576586
 			url="http://us.archive.ubuntu.com/ubuntu/pool/main/l/linux"
576586
 			extension="bz2"
576586
 			sublevel="SUBLEVEL = 0"
576586
-			taroptions="xvjf"
576586
+			troptions="xvjf"
576586
 
576586
 		elif [[ $DISTRO = debian ]]; then
576586
 
576586
@@ -478,6 +478,9 @@ cd "$SRCDIR"
576586
 make prepare >> "$LOGFILE" 2>&1 || die
576586
 cd "$TEMPDIR/output"
576586
 ld -r -o ../patch/output.o $FILES >> "$LOGFILE" 2>&1 || die
576586
+md5sum ../patch/output.o | awk '{printf "%s\0", $1}' > checksum.tmp || die
576586
+objcopy --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly  ../patch/output.o || die
576586
+rm -f checksum.tmp
576586
 cd "$TEMPDIR/patch"
576586
 KPATCH_BUILD="$SRCDIR" KPATCH_NAME="$PATCHNAME" KBUILD_EXTRA_SYMBOLS="$SYMVERSFILE" make "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
576586
 
576586
diff --git a/kpatch/kpatch b/kpatch/kpatch
576586
index 0b932a6..0e36dda 100755
576586
--- a/kpatch/kpatch
576586
+++ b/kpatch/kpatch
576586
@@ -121,6 +121,21 @@ core_module_loaded () {
576586
 	grep -q "T kpatch_register" /proc/kallsyms
576586
 }
576586
 
576586
+get_module_name () {
576586
+	echo $(readelf -p .gnu.linkonce.this_module $1 | grep '\[.*\]' | awk '{print $3}')
576586
+}
576586
+
576586
+verify_module_checksum () {
576586
+    modname=$(get_module_name $1)
576586
+    [[ -z $modname ]] && return 1
576586
+
576586
+    checksum=$(readelf -p .kpatch.checksum $1 | grep '\[.*\]' | awk '{print $3}')
576586
+    [[ -z $checksum ]] && return 1
576586
+
576586
+    sysfs_checksum=$(cat /sys/kernel/kpatch/patches/${modname}/checksum)
576586
+    [[ $checksum == $sysfs_checksum ]] || return 1
576586
+}
576586
+
576586
 load_module () {
576586
 	if ! core_module_loaded; then
576586
 		if modprobe -q kpatch; then
576586
@@ -131,6 +146,23 @@ load_module () {
576586
 			insmod "$COREMOD" || die "failed to load core module"
576586
 		fi
576586
 	fi
576586
+
576586
+	modname=$(get_module_name $1)
576586
+	moddir=/sys/kernel/kpatch/patches/$modname
576586
+	if [[ -d $moddir ]] ; then
576586
+		if [[ $(cat "${moddir}/enabled") -eq 0 ]]; then
576586
+			if verify_module_checksum $1; then # same checksum
576586
+				echo "module already loaded, re-enabling"
576586
+				echo 1 > ${moddir}/enabled || die "failed to re-enable module $modname"
576586
+				return
576586
+			else
576586
+				die "error: cannot re-enable patch module $modname, cannot verify checksum match"
576586
+			fi
576586
+		else
576586
+			die "error: module named $modname already loaded and enabled"
576586
+		fi
576586
+	fi
576586
+
576586
 	echo "loading patch module: $1"
576586
 	insmod "$1" "$2"
576586
 }
576586
-- 
576586
1.9.3
576586