lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 15 Jul 2015 16:55:06 +0800
From:	Minfei Huang <mhuang@...hat.com>
To:	jpoimboe@...hat.com, sjenning@...hat.com, jkosina@...e.cz,
	vojtech@...e.cz
Cc:	live-patching@...r.kernel.org, linux-kernel@...r.kernel.org,
	Minfei Huang <mnfhuang@...il.com>
Subject: [PATCH] livepatch: Fix the issue to make livepatch enable/disable patch correctly

From: Minfei Huang <mnfhuang@...il.com>

Livepatch will obey the stacking rule to enable/disable the patch. It
only allows to enable the patch, when it is the fist disabled patch,
disable the patch, when it is the last enabled patch.

In the livepatch code, it uses list to gather the all of the patches.
And we do not know whether the previous/next patch is patched to the
same modules or vmlinux in that way.

According to above rule, livepatch will make incorrect decision to
enable/disable the patch. Following is an example to show how livepatch
does.

- install the livepatch example module which is in samples/livepatch.
- install the third part kernel module
- install the livepatch module which is patched to the third part module
- disable the livepatch example module

We can find that we can not disable livepatch example module, although
it is the last enabled patch.

To fix this issue, we will find the corresponding patch which is patched
to the same modules or vmlinux, when we enable/disable the patch.

Signed-off-by: Minfei Huang <mnfhuang@...il.com>
---
 kernel/livepatch/core.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 4 deletions(-)

diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 6e53441..d59aec7 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -429,6 +429,27 @@ err:
 	return ret;
 }
 
+static bool is_patched_to_same(struct klp_patch *p1, struct klp_patch *p2)
+{
+	struct klp_object *obj1, *obj2;
+	bool is_mod1, is_mod2;
+
+	klp_for_each_object(p1, obj1) {
+		klp_for_each_object(p2, obj2) {
+			is_mod1 = !!klp_is_module(obj1);
+			is_mod2 = !!klp_is_module(obj2);
+
+			if (is_mod1 && is_mod2) {
+				if (!strcmp(obj1->name, obj2->name))
+					return true;
+			} else if (!is_mod1 && !is_mod2)
+				return true;
+		}
+	}
+
+	return false;
+}
+
 static void klp_disable_object(struct klp_object *obj)
 {
 	struct klp_func *func;
@@ -463,13 +484,26 @@ static int klp_enable_object(struct klp_object *obj)
 	return 0;
 }
 
+struct klp_patch *get_next_patch(struct klp_patch *patch)
+{
+	struct klp_patch *p = patch;
+
+	list_for_each_entry_continue(p, &klp_patches, list) {
+		if (is_patched_to_same(p, patch))
+			return p;
+	}
+
+	return NULL;
+}
+
 static int __klp_disable_patch(struct klp_patch *patch)
 {
+	struct klp_patch *p;
 	struct klp_object *obj;
 
 	/* enforce stacking: only the last enabled patch can be disabled */
-	if (!list_is_last(&patch->list, &klp_patches) &&
-	    list_next_entry(patch, list)->state == KLP_ENABLED)
+	p = get_next_patch(patch);
+	if (p && (p->state == KLP_ENABLED))
 		return -EBUSY;
 
 	pr_notice("disabling patch '%s'\n", patch->mod->name);
@@ -516,8 +550,21 @@ err:
 }
 EXPORT_SYMBOL_GPL(klp_disable_patch);
 
+struct klp_patch *get_prev_patch(struct klp_patch *patch)
+{
+	struct klp_patch *p = patch;
+
+	list_for_each_entry_continue_reverse(p, &klp_patches, list) {
+		if (is_patched_to_same(p, patch))
+			return p;
+	}
+
+	return NULL;
+}
+
 static int __klp_enable_patch(struct klp_patch *patch)
 {
+	struct klp_patch *p;
 	struct klp_object *obj;
 	int ret;
 
@@ -525,8 +572,8 @@ static int __klp_enable_patch(struct klp_patch *patch)
 		return -EINVAL;
 
 	/* enforce stacking: only the first disabled patch can be enabled */
-	if (patch->list.prev != &klp_patches &&
-	    list_prev_entry(patch, list)->state == KLP_DISABLED)
+	p = get_prev_patch(patch);
+	if (p && (p->state == KLP_DISABLED))
 		return -EBUSY;
 
 	pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n");
-- 
2.2.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ