3ec24776bf
Currently we do not allow patch module to unload since there is no
method to determine if a task is still running in the patched code.
The consistency model gives us the way because when the unpatching
finishes we know that all tasks were marked as safe to call an original
function. Thus every new call to the function calls the original code
and at the same time no task can be somewhere in the patched code,
because it had to leave that code to be marked as safe.
We can safely let the patch module go after that.
Completion is used for synchronization between module removal and sysfs
infrastructure in a similar way to commit 942e443127
("module: Fix
mod->mkobj.kobj potentially freed too early").
Note that we still do not allow the removal for immediate model, that is
no consistency model. The module refcount may increase in this case if
somebody disables and enables the patch several times. This should not
cause any harm.
With this change a call to try_module_get() is moved to
__klp_enable_patch from klp_register_patch to make module reference
counting symmetric (module_put() is in a patch disable path) and to
allow to take a new reference to a disabled module when being enabled.
Finally, we need to be very careful about possible races between
klp_unregister_patch(), kobject_put() functions and operations
on the related sysfs files.
kobject_put(&patch->kobj) must be called without klp_mutex. Otherwise,
it might be blocked by enabled_store() that needs the mutex as well.
In addition, enabled_store() must check if the patch was not
unregisted in the meantime.
There is no need to do the same for other kobject_put() callsites
at the moment. Their sysfs operations neither take the lock nor
they access any data that might be freed in the meantime.
There was an attempt to use kobjects the right way and prevent these
races by design. But it made the patch definition more complicated
and opened another can of worms. See
https://lkml.kernel.org/r/1464018848-4303-1-git-send-email-pmladek@suse.com
[Thanks to Petr Mladek for improving the commit message.]
Signed-off-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
109 lines
2.7 KiB
C
109 lines
2.7 KiB
C
/*
|
|
* livepatch-sample.c - Kernel Live Patching Sample Module
|
|
*
|
|
* Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/livepatch.h>
|
|
|
|
/*
|
|
* This (dumb) live patch overrides the function that prints the
|
|
* kernel boot cmdline when /proc/cmdline is read.
|
|
*
|
|
* Example:
|
|
*
|
|
* $ cat /proc/cmdline
|
|
* <your cmdline>
|
|
*
|
|
* $ insmod livepatch-sample.ko
|
|
* $ cat /proc/cmdline
|
|
* this has been live patched
|
|
*
|
|
* $ echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled
|
|
* $ cat /proc/cmdline
|
|
* <your cmdline>
|
|
*/
|
|
|
|
#include <linux/seq_file.h>
|
|
static int livepatch_cmdline_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "%s\n", "this has been live patched");
|
|
return 0;
|
|
}
|
|
|
|
static struct klp_func funcs[] = {
|
|
{
|
|
.old_name = "cmdline_proc_show",
|
|
.new_func = livepatch_cmdline_proc_show,
|
|
}, { }
|
|
};
|
|
|
|
static struct klp_object objs[] = {
|
|
{
|
|
/* name being NULL means vmlinux */
|
|
.funcs = funcs,
|
|
}, { }
|
|
};
|
|
|
|
static struct klp_patch patch = {
|
|
.mod = THIS_MODULE,
|
|
.objs = objs,
|
|
};
|
|
|
|
static int livepatch_init(void)
|
|
{
|
|
int ret;
|
|
|
|
if (!klp_have_reliable_stack() && !patch.immediate) {
|
|
/*
|
|
* WARNING: Be very careful when using 'patch.immediate' in
|
|
* your patches. It's ok to use it for simple patches like
|
|
* this, but for more complex patches which change function
|
|
* semantics, locking semantics, or data structures, it may not
|
|
* be safe. Use of this option will also prevent removal of
|
|
* the patch.
|
|
*
|
|
* See Documentation/livepatch/livepatch.txt for more details.
|
|
*/
|
|
patch.immediate = true;
|
|
pr_notice("The consistency model isn't supported for your architecture. Bypassing safety mechanisms and applying the patch immediately.\n");
|
|
}
|
|
|
|
ret = klp_register_patch(&patch);
|
|
if (ret)
|
|
return ret;
|
|
ret = klp_enable_patch(&patch);
|
|
if (ret) {
|
|
WARN_ON(klp_unregister_patch(&patch));
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void livepatch_exit(void)
|
|
{
|
|
WARN_ON(klp_unregister_patch(&patch));
|
|
}
|
|
|
|
module_init(livepatch_init);
|
|
module_exit(livepatch_exit);
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_INFO(livepatch, "Y");
|