live-patching.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Petr Mladek <pmladek@suse.com>
To: Jiri Kosina <jikos@kernel.org>,
	Josh Poimboeuf <jpoimboe@redhat.com>,
	Miroslav Benes <mbenes@suse.cz>
Cc: Joe Lawrence <joe.lawrence@redhat.com>,
	Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>,
	Nicolai Stange <nstange@suse.de>,
	live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
	Petr Mladek <pmladek@suse.com>
Subject: [POC 01/23] module: Allow to delete module also from inside kernel
Date: Fri, 17 Jan 2020 16:03:01 +0100	[thread overview]
Message-ID: <20200117150323.21801-2-pmladek@suse.com> (raw)
In-Reply-To: <20200117150323.21801-1-pmladek@suse.com>

Livepatch subsystems will need to automatically load and delete
livepatch module when the livepatched one is being removed
or when the entire livepatch is being removed.

The code stopping the kernel module is moved to separate function
so that it can be reused.

The function always have rights to do the action. Also it does not
need to search for struct module because it is already passed as
a parameter.

On the other hand, it has to make sure that the given struct module
can't be released in parallel. It is achieved by combining module_put()
and module_delete() functionality in a single function.

This patch does not change the existing behavior of delete_module
syscall.

Signed-off-by: Petr Mladek <pmladek@suse.com>

module: Add module_put_and_delete()
---
 include/linux/module.h |   5 +++
 kernel/module.c        | 119 +++++++++++++++++++++++++++++++------------------
 2 files changed, 80 insertions(+), 44 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index bd165ba68617..f69f3fd72dd5 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -623,6 +623,7 @@ extern void __module_get(struct module *module);
 extern bool try_module_get(struct module *module);
 
 extern void module_put(struct module *module);
+extern int module_put_and_delete(struct module *mod);
 
 #else /*!CONFIG_MODULE_UNLOAD*/
 static inline bool try_module_get(struct module *module)
@@ -632,6 +633,10 @@ static inline bool try_module_get(struct module *module)
 static inline void module_put(struct module *module)
 {
 }
+static inline int module_put_and_delete(struct module *mod)
+{
+	return 0;
+}
 static inline void __module_get(struct module *module)
 {
 }
diff --git a/kernel/module.c b/kernel/module.c
index b56f3224b161..b3f11524f8f9 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -964,62 +964,36 @@ EXPORT_SYMBOL(module_refcount);
 /* This exists whether we can unload or not */
 static void free_module(struct module *mod);
 
-SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
-		unsigned int, flags)
+int stop_module(struct module *mod, int flags)
 {
-	struct module *mod;
-	char name[MODULE_NAME_LEN];
-	int ret, forced = 0;
-
-	if (!capable(CAP_SYS_MODULE) || modules_disabled)
-		return -EPERM;
-
-	if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
-		return -EFAULT;
-	name[MODULE_NAME_LEN-1] = '\0';
+	int forced = 0;
 
-	audit_log_kern_module(name);
-
-	if (mutex_lock_interruptible(&module_mutex) != 0)
-		return -EINTR;
-
-	mod = find_module(name);
-	if (!mod) {
-		ret = -ENOENT;
-		goto out;
-	}
-
-	if (!list_empty(&mod->source_list)) {
-		/* Other modules depend on us: get rid of them first. */
-		ret = -EWOULDBLOCK;
-		goto out;
-	}
+	/* Other modules depend on us: get rid of them first. */
+	if (!list_empty(&mod->source_list))
+		return -EWOULDBLOCK;
 
 	/* Doing init or already dying? */
 	if (mod->state != MODULE_STATE_LIVE) {
 		/* FIXME: if (force), slam module count damn the torpedoes */
 		pr_debug("%s already dying\n", mod->name);
-		ret = -EBUSY;
-		goto out;
+		return -EBUSY;
 	}
 
 	/* If it has an init func, it must have an exit func to unload */
 	if (mod->init && !mod->exit) {
 		forced = try_force_unload(flags);
-		if (!forced) {
-			/* This module can't be removed */
-			ret = -EBUSY;
-			goto out;
-		}
+		/* This module can't be removed */
+		if (!forced)
+			return -EBUSY;
 	}
 
 	/* Stop the machine so refcounts can't move and disable module. */
-	ret = try_stop_module(mod, flags, &forced);
-	if (ret != 0)
-		goto out;
+	return try_stop_module(mod, flags, &forced);
+}
 
-	mutex_unlock(&module_mutex);
-	/* Final destruction now no one is using it. */
+/* Final destruction now no one is using it. */
+static void destruct_module(struct module *mod)
+{
 	if (mod->exit != NULL)
 		mod->exit();
 	blocking_notifier_call_chain(&module_notify_list,
@@ -1033,8 +1007,44 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
 	strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
 
 	free_module(mod);
+
 	/* someone could wait for the module in add_unformed_module() */
 	wake_up_all(&module_wq);
+}
+
+SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
+		unsigned int, flags)
+{
+	struct module *mod;
+	char name[MODULE_NAME_LEN];
+	int ret;
+
+	if (!capable(CAP_SYS_MODULE) || modules_disabled)
+		return -EPERM;
+
+	if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
+		return -EFAULT;
+	name[MODULE_NAME_LEN-1] = '\0';
+
+	audit_log_kern_module(name);
+
+	if (mutex_lock_interruptible(&module_mutex) != 0)
+		return -EINTR;
+
+	mod = find_module(name);
+	if (!mod) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ret = stop_module(mod, flags);
+	if (ret)
+		goto out;
+
+	mutex_unlock(&module_mutex);
+
+/* Final destruction now no one is using it. */
+	destruct_module(mod);
 	return 0;
 out:
 	mutex_unlock(&module_mutex);
@@ -1138,20 +1148,41 @@ bool try_module_get(struct module *module)
 }
 EXPORT_SYMBOL(try_module_get);
 
-void module_put(struct module *module)
+/* Must be called under module_mutex or with preemtion disabled */
+static void __module_put(struct module* module)
 {
 	int ret;
 
+	ret = atomic_dec_if_positive(&module->refcnt);
+	WARN_ON(ret < 0);	/* Failed to put refcount */
+	trace_module_put(module, _RET_IP_);
+}
+
+void module_put(struct module *module)
+{
 	if (module) {
 		preempt_disable();
-		ret = atomic_dec_if_positive(&module->refcnt);
-		WARN_ON(ret < 0);	/* Failed to put refcount */
-		trace_module_put(module, _RET_IP_);
+		__module_put(module);
 		preempt_enable();
 	}
 }
 EXPORT_SYMBOL(module_put);
 
+int module_put_and_delete(struct module *mod)
+{
+	int ret;
+	mutex_lock(&module_mutex);
+	__module_put(mod);
+	ret = stop_module(mod, 0);
+	mutex_unlock(&module_mutex);
+
+	if (ret)
+		return ret;
+
+	destruct_module(mod);
+	return 0;
+}
+
 #else /* !CONFIG_MODULE_UNLOAD */
 static inline void print_unload_info(struct seq_file *m, struct module *mod)
 {
-- 
2.16.4


  reply	other threads:[~2020-01-17 15:03 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-17 15:03 [POC 00/23] livepatch: Split livepatch module per-object Petr Mladek
2020-01-17 15:03 ` Petr Mladek [this message]
2020-01-21 11:11   ` [POC 01/23] module: Allow to delete module also from inside kernel Julien Thierry
2020-01-17 15:03 ` [POC 02/23] livepatch: Split livepatch modules per livepatched object Petr Mladek
2020-01-21 11:11   ` Julien Thierry
2020-01-28 12:16     ` Petr Mladek
2020-01-17 15:03 ` [POC 03/23] livepatch: Better checks of struct klp_object definition Petr Mladek
2020-01-21 11:27   ` Julien Thierry
2020-01-17 15:03 ` [POC 04/23] livepatch: Prevent loading livepatch sub-module unintentionally Petr Mladek
2020-04-03 17:54   ` Joe Lawrence
2020-01-17 15:03 ` [POC 05/23] livepatch: Initialize and free livepatch submodule Petr Mladek
2020-01-21 11:58   ` Julien Thierry
2020-01-17 15:03 ` [POC 06/23] livepatch: Enable the " Petr Mladek
2020-01-17 15:03 ` [POC 07/23] livepatch: Remove obsolete functionality from klp_module_coming() Petr Mladek
2020-01-17 15:03 ` [POC 08/23] livepatch: Automatically load livepatch module when the patch module is loaded Petr Mladek
2020-01-17 15:03 ` [POC 09/23] livepatch: Handle race when livepatches are reloaded during a module load Petr Mladek
2020-01-22 18:51   ` Julien Thierry
2020-01-17 15:03 ` [POC 10/23] livepatch: Handle modprobe exit code Petr Mladek
2020-01-17 15:03 ` [POC 11/23] livepatch: Safely detect forced transition when removing split livepatch modules Petr Mladek
2020-01-22 10:15   ` Julien Thierry
2020-01-17 15:03 ` [POC 12/23] livepatch: Automatically remove livepatch module when the object is freed Petr Mladek
2020-01-17 15:03 ` [POC 13/23] livepatch: Remove livepatch module when the livepatched module is unloaded Petr Mladek
2020-01-17 15:03 ` [POC 14/23] livepatch: Never block livepatch modules when the related module is being removed Petr Mladek
2020-01-17 15:03 ` [POC 15/23] livepatch: Prevent infinite loop when loading livepatch module Petr Mladek
2020-01-17 15:03 ` [POC 16/23] livepatch: Add patch into the global list early Petr Mladek
2020-01-17 15:03 ` [POC 17/23] livepatch: Load livepatches for modules when loading the main livepatch Petr Mladek
2020-01-17 15:03 ` [POC 18/23] module: Refactor add_unformed_module() Petr Mladek
2020-01-17 15:03 ` [POC 19/23] module/livepatch: Allow to use exported symbols from livepatch module for "vmlinux" Petr Mladek
2020-04-06 18:48   ` Joe Lawrence
2020-04-07  7:33     ` Miroslav Benes
2020-04-07 20:57       ` Joe Lawrence
2020-01-17 15:03 ` [POC 20/23] module/livepatch: Relocate local variables in the module loaded when the livepatch is being loaded Petr Mladek
2020-01-18 10:29   ` kbuild test robot
2020-04-03 18:00   ` Joe Lawrence
2020-01-17 15:03 ` [POC 21/23] livepatch: Remove obsolete arch_klp_init_object_loaded() Petr Mladek
2020-01-17 15:03 ` [POC 22/23] livepatch/module: Remove obsolete copy_module_elf() Petr Mladek
2020-04-03 18:03   ` Joe Lawrence
2020-01-17 15:03 ` [POC 23/23] module: Remove obsolete module_disable_ro() Petr Mladek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200117150323.21801-2-pmladek@suse.com \
    --to=pmladek@suse.com \
    --cc=jikos@kernel.org \
    --cc=joe.lawrence@redhat.com \
    --cc=jpoimboe@redhat.com \
    --cc=kamalesh@linux.vnet.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=nstange@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).