Blame kmod/core/core.c

Packit Service ac8aad
/*
Packit Service ac8aad
 * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
Packit Service ac8aad
 * Copyright (C) 2013-2014 Josh Poimboeuf <jpoimboe@redhat.com>
Packit Service ac8aad
 *
Packit Service ac8aad
 * This program is free software; you can redistribute it and/or
Packit Service ac8aad
 * modify it under the terms of the GNU General Public License
Packit Service ac8aad
 * as published by the Free Software Foundation; either version 2
Packit Service ac8aad
 * of the License, or (at your option) any later version.
Packit Service ac8aad
 *
Packit Service ac8aad
 * This program is distributed in the hope that it will be useful,
Packit Service ac8aad
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service ac8aad
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service ac8aad
 * GNU General Public License for more details.
Packit Service ac8aad
 *
Packit Service ac8aad
 * You should have received a copy of the GNU General Public License
Packit Service ac8aad
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit Service ac8aad
 */
Packit Service ac8aad
Packit Service ac8aad
/*
Packit Service ac8aad
 * kpatch core module
Packit Service ac8aad
 *
Packit Service ac8aad
 * Patch modules register with this module to redirect old functions to new
Packit Service ac8aad
 * functions.
Packit Service ac8aad
 *
Packit Service ac8aad
 * For each function patched by the module we must:
Packit Service ac8aad
 * - Call stop_machine
Packit Service ac8aad
 * - Ensure that no task has the old function in its call stack
Packit Service ac8aad
 * - Add the new function address to kpatch_func_hash
Packit Service ac8aad
 *
Packit Service ac8aad
 * After that, each call to the old function calls into kpatch_ftrace_handler()
Packit Service ac8aad
 * which finds the new function in kpatch_func_hash table and updates the
Packit Service ac8aad
 * return instruction pointer so that ftrace will return to the new function.
Packit Service ac8aad
 */
Packit Service ac8aad
Packit Service ac8aad
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Packit Service ac8aad
Packit Service ac8aad
#include <linux/module.h>
Packit Service ac8aad
#include <linux/slab.h>
Packit Service ac8aad
#include <linux/stop_machine.h>
Packit Service ac8aad
#include <linux/ftrace.h>
Packit Service ac8aad
#include <linux/hashtable.h>
Packit Service ac8aad
#include <linux/hardirq.h>
Packit Service ac8aad
#include <linux/uaccess.h>
Packit Service ac8aad
#include <linux/kallsyms.h>
Packit Service ac8aad
#include <linux/version.h>
Packit Service ac8aad
#include <linux/string.h>
Packit Service ac8aad
#include <linux/stacktrace.h>
Packit Service ac8aad
#include <asm/stacktrace.h>
Packit Service ac8aad
#include <asm/cacheflush.h>
Packit Service ac8aad
#include <generated/utsrelease.h>
Packit Service ac8aad
#include "kpatch.h"
Packit Service ac8aad
Packit Service ac8aad
#ifndef UTS_UBUNTU_RELEASE_ABI
Packit Service ac8aad
#define UTS_UBUNTU_RELEASE_ABI 0
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
#if !defined(CONFIG_FUNCTION_TRACER) || \
Packit Service ac8aad
	!defined(CONFIG_HAVE_FENTRY) || \
Packit Service ac8aad
	!defined(CONFIG_MODULES) || \
Packit Service ac8aad
	!defined(CONFIG_SYSFS) || \
Packit Service ac8aad
	!defined(CONFIG_STACKTRACE) || \
Packit Service ac8aad
	!defined(CONFIG_KALLSYMS_ALL)
Packit Service ac8aad
#error "CONFIG_FUNCTION_TRACER, CONFIG_HAVE_FENTRY, CONFIG_MODULES, CONFIG_SYSFS, CONFIG_KALLSYMS_ALL kernel config options are required"
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
#define KPATCH_HASH_BITS 8
Packit Service ac8aad
static DEFINE_HASHTABLE(kpatch_func_hash, KPATCH_HASH_BITS);
Packit Service ac8aad
Packit Service ac8aad
static DEFINE_SEMAPHORE(kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
static LIST_HEAD(kpmod_list);
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_num_patched;
Packit Service ac8aad
Packit Service ac8aad
struct kobject *kpatch_root_kobj;
Packit Service ac8aad
EXPORT_SYMBOL_GPL(kpatch_root_kobj);
Packit Service ac8aad
Packit Service ac8aad
struct kpatch_kallsyms_args {
Packit Service ac8aad
	const char *objname;
Packit Service ac8aad
	const char *name;
Packit Service ac8aad
	unsigned long addr;
Packit Service ac8aad
	unsigned long count;
Packit Service ac8aad
	unsigned long pos;
Packit Service ac8aad
};
Packit Service ac8aad
Packit Service da4517
struct kpatch_apply_patch_args {
Packit Service da4517
	struct kpatch_module *kpmod;
Packit Service da4517
	bool replace;
Packit Service da4517
};
Packit Service da4517
Packit Service ac8aad
/* this is a double loop, use goto instead of break */
Packit Service ac8aad
#define do_for_each_linked_func(kpmod, func) {				\
Packit Service ac8aad
	struct kpatch_object *_object;					\
Packit Service ac8aad
	list_for_each_entry(_object, &kpmod->objects, list) {		\
Packit Service ac8aad
		if (!kpatch_object_linked(_object))			\
Packit Service ac8aad
			continue;					\
Packit Service ac8aad
		list_for_each_entry(func, &_object->funcs, list) {
Packit Service ac8aad
Packit Service ac8aad
#define while_for_each_linked_func()					\
Packit Service ac8aad
		}							\
Packit Service ac8aad
	}								\
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
Packit Service ac8aad
/*
Packit Service ac8aad
 * The kpatch core module has a state machine which allows for proper
Packit Service ac8aad
 * synchronization with kpatch_ftrace_handler() when it runs in NMI context.
Packit Service ac8aad
 *
Packit Service ac8aad
 *         +-----------------------------------------------------+
Packit Service ac8aad
 *         |                                                     |
Packit Service ac8aad
 *         |                                                     +
Packit Service ac8aad
 *         v                                     +---> KPATCH_STATE_SUCCESS
Packit Service ac8aad
 * KPATCH_STATE_IDLE +---> KPATCH_STATE_UPDATING |
Packit Service ac8aad
 *         ^                                     +---> KPATCH_STATE_FAILURE
Packit Service ac8aad
 *         |                                                     +
Packit Service ac8aad
 *         |                                                     |
Packit Service ac8aad
 *         +-----------------------------------------------------+
Packit Service ac8aad
 *
Packit Service ac8aad
 * KPATCH_STATE_IDLE: No updates are pending.  The func hash is valid, and the
Packit Service ac8aad
 * reader doesn't need to check func->op.
Packit Service ac8aad
 *
Packit Service ac8aad
 * KPATCH_STATE_UPDATING: An update is in progress.  The reader must call
Packit Service ac8aad
 * kpatch_state_finish(KPATCH_STATE_FAILURE) before accessing the func hash.
Packit Service ac8aad
 *
Packit Service ac8aad
 * KPATCH_STATE_FAILURE: An update failed, and the func hash might be
Packit Service ac8aad
 * inconsistent (pending patched funcs might not have been removed yet).  If
Packit Service ac8aad
 * func->op is KPATCH_OP_PATCH, then rollback to the previous version of the
Packit Service ac8aad
 * func.
Packit Service ac8aad
 *
Packit Service ac8aad
 * KPATCH_STATE_SUCCESS: An update succeeded, but the func hash might be
Packit Service ac8aad
 * inconsistent (pending unpatched funcs might not have been removed yet).  If
Packit Service ac8aad
 * func->op is KPATCH_OP_UNPATCH, then rollback to the previous version of the
Packit Service ac8aad
 * func.
Packit Service ac8aad
 */
Packit Service ac8aad
enum {
Packit Service ac8aad
	KPATCH_STATE_IDLE,
Packit Service ac8aad
	KPATCH_STATE_UPDATING,
Packit Service ac8aad
	KPATCH_STATE_SUCCESS,
Packit Service ac8aad
	KPATCH_STATE_FAILURE,
Packit Service ac8aad
};
Packit Service ac8aad
static atomic_t kpatch_state;
Packit Service ac8aad
Packit Service ac8aad
static int (*kpatch_set_memory_rw)(unsigned long addr, int numpages);
Packit Service ac8aad
static int (*kpatch_set_memory_ro)(unsigned long addr, int numpages);
Packit Service ac8aad
Packit Service ac8aad
#define MAX_STACK_TRACE_DEPTH   64
Packit Service ac8aad
static unsigned long stack_entries[MAX_STACK_TRACE_DEPTH];
Packit Service ac8aad
static struct stack_trace trace = {
Packit Service ac8aad
	.max_entries	= ARRAY_SIZE(stack_entries),
Packit Service ac8aad
	.entries	= &stack_entries[0],
Packit Service ac8aad
};
Packit Service ac8aad
Packit Service ac8aad
static inline void kpatch_state_idle(void)
Packit Service ac8aad
{
Packit Service ac8aad
	int state = atomic_read(&kpatch_state);
Packit Service ac8aad
Packit Service ac8aad
	WARN_ON(state != KPATCH_STATE_SUCCESS && state != KPATCH_STATE_FAILURE);
Packit Service ac8aad
	atomic_set(&kpatch_state, KPATCH_STATE_IDLE);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline void kpatch_state_updating(void)
Packit Service ac8aad
{
Packit Service ac8aad
	WARN_ON(atomic_read(&kpatch_state) != KPATCH_STATE_IDLE);
Packit Service ac8aad
	atomic_set(&kpatch_state, KPATCH_STATE_UPDATING);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/* If state is updating, change it to success or failure and return new state */
Packit Service ac8aad
static inline int kpatch_state_finish(int state)
Packit Service ac8aad
{
Packit Service ac8aad
	int result;
Packit Service ac8aad
Packit Service ac8aad
	WARN_ON(state != KPATCH_STATE_SUCCESS && state != KPATCH_STATE_FAILURE);
Packit Service ac8aad
	result = atomic_cmpxchg(&kpatch_state, KPATCH_STATE_UPDATING, state);
Packit Service ac8aad
	return result == KPATCH_STATE_UPDATING ? state : result;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static struct kpatch_func *kpatch_get_func(unsigned long ip)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_func *f;
Packit Service ac8aad
Packit Service ac8aad
	/* Here, we have to use rcu safe hlist because of NMI concurrency */
Packit Service ac8aad
	hash_for_each_possible_rcu(kpatch_func_hash, f, node, ip)
Packit Service ac8aad
		if (f->old_addr == ip)
Packit Service ac8aad
			return f;
Packit Service ac8aad
	return NULL;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static struct kpatch_func *kpatch_get_prev_func(struct kpatch_func *f,
Packit Service ac8aad
						unsigned long ip)
Packit Service ac8aad
{
Packit Service ac8aad
	hlist_for_each_entry_continue_rcu(f, node)
Packit Service ac8aad
		if (f->old_addr == ip)
Packit Service ac8aad
			return f;
Packit Service ac8aad
	return NULL;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline bool kpatch_object_linked(struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	return object->mod || !strcmp(object->name, "vmlinux");
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline int kpatch_compare_addresses(unsigned long stack_addr,
Packit Service ac8aad
					   unsigned long func_addr,
Packit Service ac8aad
					   unsigned long func_size,
Packit Service ac8aad
					   const char *func_name)
Packit Service ac8aad
{
Packit Service ac8aad
	if (stack_addr >= func_addr && stack_addr < func_addr + func_size) {
Packit Service ac8aad
		pr_err("activeness safety check failed for %s\n", func_name);
Packit Service ac8aad
		return -EBUSY;
Packit Service ac8aad
	}
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_backtrace_address_verify(struct kpatch_module *kpmod,
Packit Service da4517
					   unsigned long address,
Packit Service da4517
					   bool replace)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	int i;
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service ac8aad
	/* check kpmod funcs */
Packit Service ac8aad
	do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
		unsigned long func_addr, func_size;
Packit Service ac8aad
		const char *func_name;
Packit Service ac8aad
		struct kpatch_func *active_func;
Packit Service ac8aad
Packit Service ac8aad
		if (func->force)
Packit Service ac8aad
			continue;
Packit Service ac8aad
Packit Service ac8aad
		active_func = kpatch_get_func(func->old_addr);
Packit Service ac8aad
		if (!active_func) {
Packit Service ac8aad
			/* patching an unpatched func */
Packit Service ac8aad
			func_addr = func->old_addr;
Packit Service ac8aad
			func_size = func->old_size;
Packit Service ac8aad
			func_name = func->name;
Packit Service ac8aad
		} else {
Packit Service ac8aad
			/* repatching or unpatching */
Packit Service ac8aad
			func_addr = active_func->new_addr;
Packit Service ac8aad
			func_size = active_func->new_size;
Packit Service ac8aad
			func_name = active_func->name;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		ret = kpatch_compare_addresses(address, func_addr,
Packit Service ac8aad
					       func_size, func_name);
Packit Service ac8aad
		if (ret)
Packit Service ac8aad
			return ret;
Packit Service ac8aad
	} while_for_each_linked_func();
Packit Service ac8aad
Packit Service ac8aad
	/* in the replace case, need to check the func hash as well */
Packit Service da4517
	if (replace) {
Packit Service da4517
		hash_for_each_rcu(kpatch_func_hash, i, func, node) {
Packit Service da4517
			if (func->op != KPATCH_OP_UNPATCH || func->force)
Packit Service da4517
				continue;
Packit Service da4517
Packit Service ac8aad
			ret = kpatch_compare_addresses(address,
Packit Service ac8aad
						       func->new_addr,
Packit Service ac8aad
						       func->new_size,
Packit Service ac8aad
						       func->name);
Packit Service ac8aad
			if (ret)
Packit Service ac8aad
				return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/*
Packit Service ac8aad
 * Verify activeness safety, i.e. that none of the to-be-patched functions are
Packit Service ac8aad
 * on the stack of any task.
Packit Service ac8aad
 *
Packit Service ac8aad
 * This function is called from stop_machine() context.
Packit Service ac8aad
 */
Packit Service da4517
static int kpatch_verify_activeness_safety(struct kpatch_module *kpmod,
Packit Service da4517
					   bool replace)
Packit Service ac8aad
{
Packit Service ac8aad
	struct task_struct *g, *t;
Packit Service ac8aad
	int i;
Packit Service ac8aad
	int ret = 0;
Packit Service ac8aad
Packit Service ac8aad
	/* Check the stacks of all tasks. */
Packit Service ac8aad
	do_each_thread(g, t) {
Packit Service ac8aad
Packit Service ac8aad
		trace.nr_entries = 0;
Packit Service ac8aad
		save_stack_trace_tsk(t, &trace);
Packit Service ac8aad
		if (trace.nr_entries >= trace.max_entries) {
Packit Service ac8aad
			ret = -EBUSY;
Packit Service ac8aad
			pr_err("more than %u trace entries!\n",
Packit Service ac8aad
			       trace.max_entries);
Packit Service ac8aad
			goto out;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
                for (i = 0; i < trace.nr_entries; i++) {
Packit Service ac8aad
			if (trace.entries[i] == ULONG_MAX)
Packit Service ac8aad
				break;
Packit Service ac8aad
			ret = kpatch_backtrace_address_verify(kpmod,
Packit Service da4517
							      trace.entries[i],
Packit Service da4517
							      replace);
Packit Service ac8aad
			if (ret)
Packit Service ac8aad
				goto out;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
	} while_each_thread(g, t);
Packit Service ac8aad
Packit Service ac8aad
out:
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		pr_err("PID: %d Comm: %.20s\n", t->pid, t->comm);
Packit Service ac8aad
		for (i = 0; i < trace.nr_entries; i++) {
Packit Service ac8aad
			if (trace.entries[i] == ULONG_MAX)
Packit Service ac8aad
				break;
Packit Service ac8aad
			pr_err("  [<%pK>] %pB\n",
Packit Service ac8aad
			       (void *)trace.entries[i],
Packit Service ac8aad
			       (void *)trace.entries[i]);
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline int pre_patch_callback(struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service ac8aad
	if (kpatch_object_linked(object) &&
Packit Service ac8aad
	    object->pre_patch_callback) {
Packit Service ac8aad
		ret = (*object->pre_patch_callback)(object);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			object->callbacks_enabled = false;
Packit Service ac8aad
			return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
	object->callbacks_enabled = true;
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline void post_patch_callback(struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	if (kpatch_object_linked(object) &&
Packit Service ac8aad
	    object->post_patch_callback &&
Packit Service ac8aad
	    object->callbacks_enabled)
Packit Service ac8aad
		(*object->post_patch_callback)(object);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline void pre_unpatch_callback(struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	if (kpatch_object_linked(object) &&
Packit Service ac8aad
	    object->pre_unpatch_callback &&
Packit Service ac8aad
	    object->callbacks_enabled)
Packit Service ac8aad
		(*object->pre_unpatch_callback)(object);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static inline void post_unpatch_callback(struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	if (kpatch_object_linked(object) &&
Packit Service ac8aad
	    object->post_unpatch_callback &&
Packit Service ac8aad
	    object->callbacks_enabled)
Packit Service ac8aad
		(*object->post_unpatch_callback)(object);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/* Called from stop_machine */
Packit Service ac8aad
static int kpatch_apply_patch(void *data)
Packit Service ac8aad
{
Packit Service da4517
	struct kpatch_apply_patch_args *args = data;
Packit Service da4517
	struct kpatch_module *kpmod;
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service da4517
	struct hlist_node *tmp;
Packit Service ac8aad
	struct kpatch_object *object;
Packit Service ac8aad
	int ret;
Packit Service da4517
	int i;
Packit Service ac8aad
Packit Service da4517
	kpmod = args->kpmod;
Packit Service da4517
Packit Service da4517
	ret = kpatch_verify_activeness_safety(kpmod, args->replace);
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		kpatch_state_finish(KPATCH_STATE_FAILURE);
Packit Service ac8aad
		return ret;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	/* tentatively add the new funcs to the global func hash */
Packit Service ac8aad
	do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
		hash_add_rcu(kpatch_func_hash, &func->node, func->old_addr);
Packit Service ac8aad
	} while_for_each_linked_func();
Packit Service ac8aad
Packit Service ac8aad
	/* memory barrier between func hash add and state change */
Packit Service ac8aad
	smp_wmb();
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service ac8aad
	 * Check if any inconsistent NMI has happened while updating.  If not,
Packit Service ac8aad
	 * move to success state.
Packit Service ac8aad
	 */
Packit Service ac8aad
	ret = kpatch_state_finish(KPATCH_STATE_SUCCESS);
Packit Service ac8aad
	if (ret == KPATCH_STATE_FAILURE) {
Packit Service ac8aad
		pr_err("NMI activeness safety check failed\n");
Packit Service ac8aad
Packit Service ac8aad
		/* Failed, we have to rollback patching process */
Packit Service ac8aad
		do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
			hash_del_rcu(&func->node);
Packit Service ac8aad
		} while_for_each_linked_func();
Packit Service ac8aad
Packit Service da4517
		return -EBUSY;
Packit Service da4517
	}
Packit Service da4517
Packit Service da4517
	/*
Packit Service da4517
	 * The new patch has been applied successfully. Remove the functions
Packit Service da4517
	 * provided by the replaced patches (if any) from hash, to make sure
Packit Service da4517
	 * they will not be executed anymore.
Packit Service da4517
	 */
Packit Service da4517
	if (args->replace) {
Packit Service da4517
		hash_for_each_safe(kpatch_func_hash, i, tmp, func, node) {
Packit Service da4517
			if (func->op != KPATCH_OP_UNPATCH)
Packit Service da4517
				continue;
Packit Service da4517
			hash_del_rcu(&func->node);
Packit Service da4517
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	/* run any user-defined post-patch callbacks */
Packit Service ac8aad
	list_for_each_entry(object, &kpmod->objects, list)
Packit Service ac8aad
		post_patch_callback(object);
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/* Called from stop_machine */
Packit Service ac8aad
static int kpatch_remove_patch(void *data)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_module *kpmod = data;
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	struct kpatch_object *object;
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service da4517
	ret = kpatch_verify_activeness_safety(kpmod, false);
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		kpatch_state_finish(KPATCH_STATE_FAILURE);
Packit Service ac8aad
		return ret;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	/* run any user-defined pre-unpatch callbacks */
Packit Service ac8aad
	list_for_each_entry(object, &kpmod->objects, list)
Packit Service ac8aad
		pre_unpatch_callback(object);
Packit Service ac8aad
Packit Service ac8aad
	/* Check if any inconsistent NMI has happened while updating */
Packit Service ac8aad
	ret = kpatch_state_finish(KPATCH_STATE_SUCCESS);
Packit Service ac8aad
	if (ret == KPATCH_STATE_FAILURE) {
Packit Service ac8aad
		ret = -EBUSY;
Packit Service ac8aad
		goto err;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	/* Succeeded, remove all updating funcs from hash table */
Packit Service ac8aad
	do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
		hash_del_rcu(&func->node);
Packit Service ac8aad
	} while_for_each_linked_func();
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
Packit Service ac8aad
err:
Packit Service ac8aad
	/* undo pre-unpatch callbacks by calling post-patch counterparts */
Packit Service ac8aad
	list_for_each_entry(object, &kpmod->objects, list)
Packit Service ac8aad
		post_patch_callback(object);
Packit Service ac8aad
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/*
Packit Service ac8aad
 * This is where the magic happens.  Update regs->ip to tell ftrace to return
Packit Service ac8aad
 * to the new function.
Packit Service ac8aad
 *
Packit Service ac8aad
 * If there are multiple patch modules that have registered to patch the same
Packit Service ac8aad
 * function, the last one to register wins, as it'll be first in the hash
Packit Service ac8aad
 * bucket.
Packit Service ac8aad
 */
Packit Service ac8aad
static void notrace
Packit Service ac8aad
kpatch_ftrace_handler(unsigned long ip, unsigned long parent_ip,
Packit Service ac8aad
		      struct ftrace_ops *fops, struct pt_regs *regs)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	int state;
Packit Service ac8aad
Packit Service ac8aad
	preempt_disable_notrace();
Packit Service ac8aad
Packit Service ac8aad
	if (likely(!in_nmi()))
Packit Service ac8aad
		func = kpatch_get_func(ip);
Packit Service ac8aad
	else {
Packit Service ac8aad
		/* Checking for NMI inconsistency */
Packit Service ac8aad
		state = kpatch_state_finish(KPATCH_STATE_FAILURE);
Packit Service ac8aad
Packit Service ac8aad
		/* no memory reordering between state and func hash read */
Packit Service ac8aad
		smp_rmb();
Packit Service ac8aad
Packit Service ac8aad
		func = kpatch_get_func(ip);
Packit Service ac8aad
Packit Service ac8aad
		if (likely(state == KPATCH_STATE_IDLE))
Packit Service ac8aad
			goto done;
Packit Service ac8aad
Packit Service ac8aad
		if (state == KPATCH_STATE_SUCCESS) {
Packit Service ac8aad
			/*
Packit Service ac8aad
			 * Patching succeeded.  If the function was being
Packit Service ac8aad
			 * unpatched, roll back to the previous version.
Packit Service ac8aad
			 */
Packit Service ac8aad
			if (func && func->op == KPATCH_OP_UNPATCH)
Packit Service ac8aad
				func = kpatch_get_prev_func(func, ip);
Packit Service ac8aad
		} else {
Packit Service ac8aad
			/*
Packit Service ac8aad
			 * Patching failed.  If the function was being patched,
Packit Service ac8aad
			 * roll back to the previous version.
Packit Service ac8aad
			 */
Packit Service ac8aad
			if (func && func->op == KPATCH_OP_PATCH)
Packit Service ac8aad
				func = kpatch_get_prev_func(func, ip);
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
done:
Packit Service ac8aad
	if (func)
Packit Service ac8aad
		regs->ip = func->new_addr + MCOUNT_INSN_SIZE;
Packit Service ac8aad
Packit Service ac8aad
	preempt_enable_notrace();
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
Packit Service ac8aad
#define FTRACE_OPS_FL_IPMODIFY 0
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
static struct ftrace_ops kpatch_ftrace_ops __read_mostly = {
Packit Service ac8aad
	.func = kpatch_ftrace_handler,
Packit Service ac8aad
	.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY,
Packit Service ac8aad
};
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_ftrace_add_func(unsigned long ip)
Packit Service ac8aad
{
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service ac8aad
	/* check if any other patch modules have also patched this func */
Packit Service ac8aad
	if (kpatch_get_func(ip))
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	ret = ftrace_set_filter_ip(&kpatch_ftrace_ops, ip, 0, 0);
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		pr_err("can't set ftrace filter at address 0x%lx\n", ip);
Packit Service ac8aad
		return ret;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	if (!kpatch_num_patched) {
Packit Service ac8aad
		ret = register_ftrace_function(&kpatch_ftrace_ops);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			pr_err("can't register ftrace handler\n");
Packit Service ac8aad
			ftrace_set_filter_ip(&kpatch_ftrace_ops, ip, 1, 0);
Packit Service ac8aad
			return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
	kpatch_num_patched++;
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_ftrace_remove_func(unsigned long ip)
Packit Service ac8aad
{
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service ac8aad
	/* check if any other patch modules have also patched this func */
Packit Service ac8aad
	if (kpatch_get_func(ip))
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	if (kpatch_num_patched == 1) {
Packit Service ac8aad
		ret = unregister_ftrace_function(&kpatch_ftrace_ops);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			pr_err("can't unregister ftrace handler\n");
Packit Service ac8aad
			return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
	kpatch_num_patched--;
Packit Service ac8aad
Packit Service ac8aad
	ret = ftrace_set_filter_ip(&kpatch_ftrace_ops, ip, 1, 0);
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		pr_err("can't remove ftrace filter at address 0x%lx\n", ip);
Packit Service ac8aad
		return ret;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_kallsyms_callback(void *data, const char *name,
Packit Service ac8aad
					 struct module *mod,
Packit Service ac8aad
					 unsigned long addr)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_kallsyms_args *args = data;
Packit Service ac8aad
	bool vmlinux = !strcmp(args->objname, "vmlinux");
Packit Service ac8aad
Packit Service ac8aad
	if ((mod && vmlinux) || (!mod && !vmlinux))
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	if (strcmp(args->name, name))
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	if (!vmlinux && strcmp(args->objname, mod->name))
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	args->addr = addr;
Packit Service ac8aad
	args->count++;
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service ac8aad
	 * Finish the search when the symbol is found for the desired position
Packit Service ac8aad
	 * or the position is not defined for a non-unique symbol.
Packit Service ac8aad
	 */
Packit Service ac8aad
	if ((args->pos && (args->count == args->pos)) ||
Packit Service ac8aad
	    (!args->pos && (args->count > 1))) {
Packit Service ac8aad
		return 1;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_find_object_symbol(const char *objname, const char *name,
Packit Service ac8aad
				     unsigned long sympos, unsigned long *addr)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_kallsyms_args args = {
Packit Service ac8aad
		.objname = objname,
Packit Service ac8aad
		.name = name,
Packit Service ac8aad
		.addr = 0,
Packit Service ac8aad
		.count = 0,
Packit Service ac8aad
		.pos = sympos,
Packit Service ac8aad
	};
Packit Service ac8aad
Packit Service ac8aad
	mutex_lock(&module_mutex);
Packit Service ac8aad
	kallsyms_on_each_symbol(kpatch_kallsyms_callback, &args);
Packit Service ac8aad
	mutex_unlock(&module_mutex);
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service ac8aad
	 * Ensure an address was found. If sympos is 0, ensure symbol is unique;
Packit Service ac8aad
	 * otherwise ensure the symbol position count matches sympos.
Packit Service ac8aad
	 */
Packit Service ac8aad
	if (args.addr == 0)
Packit Service ac8aad
		pr_err("symbol '%s' not found in symbol table\n", name);
Packit Service ac8aad
	else if (args.count > 1 && sympos == 0) {
Packit Service ac8aad
		pr_err("unresolvable ambiguity for symbol '%s' in object '%s'\n",
Packit Service ac8aad
		       name, objname);
Packit Service ac8aad
	} else if (sympos != args.count && sympos > 0) {
Packit Service ac8aad
		pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
Packit Service ac8aad
		       sympos, name, objname);
Packit Service ac8aad
	} else {
Packit Service ac8aad
		*addr = args.addr;
Packit Service ac8aad
		return 0;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	*addr = 0;
Packit Service ac8aad
	return -EINVAL;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/*
Packit Service ac8aad
 * External symbols are located outside the parent object (where the parent
Packit Service ac8aad
 * object is either vmlinux or the kmod being patched).
Packit Service ac8aad
 */
Packit Service ac8aad
static int kpatch_find_external_symbol(const char *objname, const char *name,
Packit Service ac8aad
				       unsigned long sympos, unsigned long *addr)
Packit Service ac8aad
Packit Service ac8aad
{
Packit Service ac8aad
	const struct kernel_symbol *sym;
Packit Service ac8aad
Packit Service ac8aad
	/* first, check if it's an exported symbol */
Packit Service ac8aad
	preempt_disable();
Packit Service ac8aad
	sym = find_symbol(name, NULL, NULL, true, true);
Packit Service ac8aad
	preempt_enable();
Packit Service ac8aad
	if (sym) {
Packit Service da4517
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
Packit Service da4517
		*addr = (unsigned long)offset_to_ptr(&sym->value_offset);
Packit Service da4517
#else
Packit Service ac8aad
		*addr = sym->value;
Packit Service da4517
#endif
Packit Service ac8aad
		return 0;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	/* otherwise check if it's in another .o within the patch module */
Packit Service ac8aad
	return kpatch_find_object_symbol(objname, name, sympos, addr);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_write_relocations(struct kpatch_module *kpmod,
Packit Service ac8aad
				    struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	int ret, size, readonly = 0, numpages;
Packit Service ac8aad
	struct kpatch_dynrela *dynrela;
Packit Service ac8aad
	u64 loc, val;
Packit Service ac8aad
#if (( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) ) || \
Packit Service ac8aad
     ( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
Packit Service ac8aad
      UTS_UBUNTU_RELEASE_ABI >= 7 ) \
Packit Service ac8aad
    )
Packit Service ac8aad
	unsigned long core = (unsigned long)kpmod->mod->core_layout.base;
Packit Service ac8aad
	unsigned long core_size = kpmod->mod->core_layout.size;
Packit Service ac8aad
#else
Packit Service ac8aad
	unsigned long core = (unsigned long)kpmod->mod->module_core;
Packit Service ac8aad
	unsigned long core_size = kpmod->mod->core_size;
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(dynrela, &object->dynrelas, list) {
Packit Service ac8aad
		if (dynrela->external)
Packit Service ac8aad
			ret = kpatch_find_external_symbol(kpmod->mod->name,
Packit Service ac8aad
							  dynrela->name,
Packit Service ac8aad
							  dynrela->sympos,
Packit Service ac8aad
							  &dynrela->src);
Packit Service ac8aad
		else
Packit Service ac8aad
			ret = kpatch_find_object_symbol(object->name,
Packit Service ac8aad
							dynrela->name,
Packit Service ac8aad
							dynrela->sympos,
Packit Service ac8aad
							&dynrela->src);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			pr_err("unable to find symbol '%s'\n", dynrela->name);
Packit Service ac8aad
			return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		switch (dynrela->type) {
Packit Service ac8aad
		case R_X86_64_NONE:
Packit Service ac8aad
			continue;
Packit Service ac8aad
		case R_X86_64_PC32:
Packit Service da4517
		case R_X86_64_PLT32:
Packit Service ac8aad
			loc = dynrela->dest;
Packit Service ac8aad
			val = (u32)(dynrela->src + dynrela->addend -
Packit Service ac8aad
				    dynrela->dest);
Packit Service ac8aad
			size = 4;
Packit Service ac8aad
			break;
Packit Service ac8aad
		case R_X86_64_32S:
Packit Service ac8aad
			loc = dynrela->dest;
Packit Service ac8aad
			val = (s32)dynrela->src + dynrela->addend;
Packit Service ac8aad
			size = 4;
Packit Service ac8aad
			break;
Packit Service ac8aad
		case R_X86_64_64:
Packit Service ac8aad
			loc = dynrela->dest;
Packit Service da4517
			val = dynrela->src + dynrela->addend;
Packit Service ac8aad
			size = 8;
Packit Service ac8aad
			break;
Packit Service ac8aad
		default:
Packit Service ac8aad
			pr_err("unsupported rela type %ld for source %s (0x%lx <- 0x%lx)\n",
Packit Service ac8aad
			       dynrela->type, dynrela->name, dynrela->dest,
Packit Service ac8aad
			       dynrela->src);
Packit Service ac8aad
			return -EINVAL;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		if (loc < core || loc >= core + core_size) {
Packit Service ac8aad
			pr_err("bad dynrela location 0x%llx for symbol %s\n",
Packit Service ac8aad
			       loc, dynrela->name);
Packit Service ac8aad
			return -EINVAL;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		/*
Packit Service ac8aad
		 * Skip it if the instruction to be relocated has been
Packit Service ac8aad
		 * changed already (paravirt or alternatives may do this).
Packit Service ac8aad
		 */
Packit Service ac8aad
		if (memchr_inv((void *)loc, 0, size)) {
Packit Service ac8aad
			pr_notice("Skipped dynrela for %s (0x%lx <- 0x%lx): the instruction has been changed already.\n",
Packit Service ac8aad
				  dynrela->name, dynrela->dest, dynrela->src);
Packit Service ac8aad
			pr_notice_once(
Packit Service ac8aad
"This is not necessarily a bug but it may indicate in some cases "
Packit Service ac8aad
"that the binary patch does not handle paravirt operations, alternatives or the like properly.\n");
Packit Service ac8aad
			continue;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
#if defined(CONFIG_DEBUG_SET_MODULE_RONX) || defined(CONFIG_ARCH_HAS_SET_MEMORY)
Packit Service ac8aad
#if (( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) ) || \
Packit Service ac8aad
     ( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
Packit Service ac8aad
      UTS_UBUNTU_RELEASE_ABI >= 7 ) \
Packit Service ac8aad
    )
Packit Service ac8aad
               readonly = (loc < core + kpmod->mod->core_layout.ro_size);
Packit Service ac8aad
#else
Packit Service ac8aad
               readonly = (loc < core + kpmod->mod->core_ro_size);
Packit Service ac8aad
#endif
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
		numpages = (PAGE_SIZE - (loc & ~PAGE_MASK) >= size) ? 1 : 2;
Packit Service ac8aad
Packit Service ac8aad
		if (readonly)
Packit Service ac8aad
			kpatch_set_memory_rw(loc & PAGE_MASK, numpages);
Packit Service ac8aad
Packit Service ac8aad
		ret = probe_kernel_write((void *)loc, &val, size);
Packit Service ac8aad
Packit Service ac8aad
		if (readonly)
Packit Service ac8aad
			kpatch_set_memory_ro(loc & PAGE_MASK, numpages);
Packit Service ac8aad
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			pr_err("write to 0x%llx failed for symbol %s\n",
Packit Service ac8aad
			       loc, dynrela->name);
Packit Service ac8aad
			return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_unlink_object(struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(func, &object->funcs, list) {
Packit Service ac8aad
		if (!func->old_addr)
Packit Service ac8aad
			continue;
Packit Service ac8aad
		ret = kpatch_ftrace_remove_func(func->old_addr);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			WARN(1, "can't unregister ftrace for address 0x%lx\n",
Packit Service ac8aad
			     func->old_addr);
Packit Service ac8aad
			return ret;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	if (object->mod) {
Packit Service ac8aad
		module_put(object->mod);
Packit Service ac8aad
		object->mod = NULL;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
/*
Packit Service ac8aad
 * Link to a to-be-patched object in preparation for patching it.
Packit Service ac8aad
 *
Packit Service ac8aad
 * - Find the object module
Packit Service ac8aad
 * - Write patch module relocations which reference the object
Packit Service ac8aad
 * - Calculate the patched functions' addresses
Packit Service ac8aad
 * - Register them with ftrace
Packit Service ac8aad
 */
Packit Service ac8aad
static int kpatch_link_object(struct kpatch_module *kpmod,
Packit Service ac8aad
			      struct kpatch_object *object)
Packit Service ac8aad
{
Packit Service ac8aad
	struct module *mod = NULL;
Packit Service ac8aad
	struct kpatch_func *func, *func_err = NULL;
Packit Service ac8aad
	int ret;
Packit Service ac8aad
	bool vmlinux = !strcmp(object->name, "vmlinux");
Packit Service ac8aad
Packit Service ac8aad
	if (!vmlinux) {
Packit Service ac8aad
		mutex_lock(&module_mutex);
Packit Service ac8aad
		mod = find_module(object->name);
Packit Service ac8aad
		if (!mod) {
Packit Service ac8aad
			/*
Packit Service ac8aad
			 * The module hasn't been loaded yet.  We can patch it
Packit Service ac8aad
			 * later in kpatch_module_notify().
Packit Service ac8aad
			 */
Packit Service ac8aad
			mutex_unlock(&module_mutex);
Packit Service ac8aad
			return 0;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		/* should never fail because we have the mutex */
Packit Service ac8aad
		WARN_ON(!try_module_get(mod));
Packit Service ac8aad
		mutex_unlock(&module_mutex);
Packit Service ac8aad
		object->mod = mod;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	ret = kpatch_write_relocations(kpmod, object);
Packit Service ac8aad
	if (ret)
Packit Service ac8aad
		goto err_put;
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(func, &object->funcs, list) {
Packit Service ac8aad
Packit Service ac8aad
		/* lookup the old location */
Packit Service ac8aad
		ret = kpatch_find_object_symbol(object->name,
Packit Service ac8aad
						func->name,
Packit Service ac8aad
						func->sympos,
Packit Service ac8aad
						&func->old_addr);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			func_err = func;
Packit Service ac8aad
			goto err_ftrace;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		/* add to ftrace filter and register handler if needed */
Packit Service ac8aad
		ret = kpatch_ftrace_add_func(func->old_addr);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			func_err = func;
Packit Service ac8aad
			goto err_ftrace;
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
Packit Service ac8aad
err_ftrace:
Packit Service ac8aad
	list_for_each_entry(func, &object->funcs, list) {
Packit Service ac8aad
		if (func == func_err)
Packit Service ac8aad
			break;
Packit Service ac8aad
		WARN_ON(kpatch_ftrace_remove_func(func->old_addr));
Packit Service ac8aad
	}
Packit Service ac8aad
err_put:
Packit Service ac8aad
	if (!vmlinux)
Packit Service ac8aad
		module_put(mod);
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_module_notify_coming(struct notifier_block *nb,
Packit Service ac8aad
				       unsigned long action, void *data)
Packit Service ac8aad
{
Packit Service ac8aad
	struct module *mod = data;
Packit Service ac8aad
	struct kpatch_module *kpmod;
Packit Service ac8aad
	struct kpatch_object *object;
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	int ret = 0;
Packit Service ac8aad
	bool found = false;
Packit Service ac8aad
Packit Service ac8aad
	if (action != MODULE_STATE_COMING)
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	down(&kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(kpmod, &kpmod_list, list) {
Packit Service ac8aad
		list_for_each_entry(object, &kpmod->objects, list) {
Packit Service ac8aad
			if (kpatch_object_linked(object))
Packit Service ac8aad
				continue;
Packit Service ac8aad
			if (!strcmp(object->name, mod->name)) {
Packit Service ac8aad
				found = true;
Packit Service ac8aad
				goto done;
Packit Service ac8aad
			}
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
done:
Packit Service ac8aad
	if (!found)
Packit Service ac8aad
		goto out;
Packit Service ac8aad
Packit Service ac8aad
	ret = kpatch_link_object(kpmod, object);
Packit Service ac8aad
	if (ret)
Packit Service ac8aad
		goto out;
Packit Service ac8aad
Packit Service ac8aad
	BUG_ON(!object->mod);
Packit Service ac8aad
Packit Service ac8aad
	pr_notice("patching newly loaded module '%s'\n", object->name);
Packit Service ac8aad
Packit Service ac8aad
	/* run user-defined pre-patch callback */
Packit Service ac8aad
	ret = pre_patch_callback(object);
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		pr_err("pre-patch callback failed!\n");
Packit Service ac8aad
		goto out;	/* and WARN */
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	/* add to the global func hash */
Packit Service ac8aad
	list_for_each_entry(func, &object->funcs, list)
Packit Service ac8aad
		hash_add_rcu(kpatch_func_hash, &func->node, func->old_addr);
Packit Service ac8aad
Packit Service ac8aad
	/* run user-defined post-patch callback */
Packit Service ac8aad
	post_patch_callback(object);
Packit Service ac8aad
out:
Packit Service ac8aad
	up(&kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
	/* no way to stop the module load on error */
Packit Service ac8aad
	WARN(ret, "error (%d) patching newly loaded module '%s'\n", ret,
Packit Service ac8aad
	     object->name);
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_module_notify_going(struct notifier_block *nb,
Packit Service ac8aad
				      unsigned long action, void *data)
Packit Service ac8aad
{
Packit Service ac8aad
	struct module *mod = data;
Packit Service ac8aad
	struct kpatch_module *kpmod;
Packit Service ac8aad
	struct kpatch_object *object;
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	bool found = false;
Packit Service ac8aad
Packit Service ac8aad
	if (action != MODULE_STATE_GOING)
Packit Service ac8aad
		return 0;
Packit Service ac8aad
Packit Service ac8aad
	down(&kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(kpmod, &kpmod_list, list) {
Packit Service ac8aad
		list_for_each_entry(object, &kpmod->objects, list) {
Packit Service ac8aad
			if (!kpatch_object_linked(object))
Packit Service ac8aad
				continue;
Packit Service ac8aad
			if (!strcmp(object->name, mod->name)) {
Packit Service ac8aad
				found = true;
Packit Service ac8aad
				goto done;
Packit Service ac8aad
			}
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
done:
Packit Service ac8aad
	if (!found)
Packit Service ac8aad
		goto out;
Packit Service ac8aad
Packit Service ac8aad
	/* run user-defined pre-unpatch callback */
Packit Service ac8aad
	pre_unpatch_callback(object);
Packit Service ac8aad
Packit Service ac8aad
	/* remove from the global func hash */
Packit Service ac8aad
	list_for_each_entry(func, &object->funcs, list)
Packit Service ac8aad
		hash_del_rcu(&func->node);
Packit Service ac8aad
Packit Service ac8aad
	/* run user-defined pre-unpatch callback */
Packit Service ac8aad
	post_unpatch_callback(object);
Packit Service ac8aad
Packit Service ac8aad
	kpatch_unlink_object(object);
Packit Service ac8aad
Packit Service ac8aad
out:
Packit Service ac8aad
	up(&kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service da4517
/*
Packit Service da4517
 * Remove the obsolete functions from the ftrace filter.
Packit Service da4517
 * Return 1 if one or more of such functions have 'force' flag set,
Packit Service da4517
 * 0 otherwise.
Packit Service da4517
 */
Packit Service da4517
static int kpatch_ftrace_remove_unpatched_funcs(void)
Packit Service da4517
{
Packit Service da4517
	struct kpatch_module *kpmod;
Packit Service da4517
	struct kpatch_func *func;
Packit Service da4517
	int force = 0;
Packit Service da4517
Packit Service da4517
	list_for_each_entry(kpmod, &kpmod_list, list) {
Packit Service da4517
		do_for_each_linked_func(kpmod, func) {
Packit Service da4517
			if (func->op != KPATCH_OP_UNPATCH)
Packit Service da4517
				continue;
Packit Service da4517
			if (func->force)
Packit Service da4517
				force = 1;
Packit Service da4517
			WARN_ON(kpatch_ftrace_remove_func(func->old_addr));
Packit Service da4517
		} while_for_each_linked_func();
Packit Service da4517
	}
Packit Service da4517
Packit Service da4517
	return force;
Packit Service da4517
}
Packit Service da4517
Packit Service ac8aad
int kpatch_register(struct kpatch_module *kpmod, bool replace)
Packit Service ac8aad
{
Packit Service da4517
	int ret, i;
Packit Service ac8aad
	struct kpatch_object *object, *object_err = NULL;
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
Packit Service da4517
	struct kpatch_apply_patch_args args = {
Packit Service da4517
		.kpmod = kpmod,
Packit Service da4517
		.replace = replace,
Packit Service da4517
	};
Packit Service da4517
Packit Service ac8aad
	if (!kpmod->mod || list_empty(&kpmod->objects))
Packit Service ac8aad
		return -EINVAL;
Packit Service ac8aad
Packit Service ac8aad
	down(&kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
	if (kpmod->enabled) {
Packit Service ac8aad
		ret = -EINVAL;
Packit Service ac8aad
		goto err_up;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	list_add_tail(&kpmod->list, &kpmod_list);
Packit Service ac8aad
Packit Service ac8aad
	if (!try_module_get(kpmod->mod)) {
Packit Service ac8aad
		ret = -ENODEV;
Packit Service ac8aad
		goto err_list;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(object, &kpmod->objects, list) {
Packit Service ac8aad
Packit Service ac8aad
		ret = kpatch_link_object(kpmod, object);
Packit Service ac8aad
		if (ret) {
Packit Service ac8aad
			object_err = object;
Packit Service ac8aad
			goto err_unlink;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		if (!kpatch_object_linked(object)) {
Packit Service ac8aad
			pr_notice("delaying patch of unloaded module '%s'\n",
Packit Service ac8aad
				  object->name);
Packit Service ac8aad
			continue;
Packit Service ac8aad
		}
Packit Service ac8aad
Packit Service ac8aad
		if (strcmp(object->name, "vmlinux"))
Packit Service ac8aad
			pr_notice("patching module '%s'\n", object->name);
Packit Service ac8aad
Packit Service ac8aad
		list_for_each_entry(func, &object->funcs, list)
Packit Service ac8aad
			func->op = KPATCH_OP_PATCH;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	if (replace)
Packit Service ac8aad
		hash_for_each_rcu(kpatch_func_hash, i, func, node)
Packit Service ac8aad
			func->op = KPATCH_OP_UNPATCH;
Packit Service ac8aad
Packit Service ac8aad
	/* memory barrier between func hash and state write */
Packit Service ac8aad
	smp_wmb();
Packit Service ac8aad
Packit Service ac8aad
	kpatch_state_updating();
Packit Service ac8aad
Packit Service da4517
	/* run any user-defined pre-patch callbacks */
Packit Service da4517
	list_for_each_entry(object, &kpmod->objects, list) {
Packit Service da4517
		ret = pre_patch_callback(object);
Packit Service da4517
		if(ret){
Packit Service da4517
			pr_err("pre-patch callback failed!\n");
Packit Service da4517
			kpatch_state_finish(KPATCH_STATE_FAILURE);
Packit Service da4517
			break;
Packit Service da4517
		}
Packit Service da4517
	}
Packit Service da4517
Packit Service da4517
	/* if pre_patch_callback succeed. */
Packit Service da4517
	if (!ret) {
Packit Service da4517
		/*
Packit Service da4517
		 * Idle the CPUs, verify activeness safety, and atomically make the new
Packit Service da4517
		 * functions visible to the ftrace handler.
Packit Service da4517
		 */
Packit Service da4517
		ret = stop_machine(kpatch_apply_patch, &args, NULL);
Packit Service da4517
	}
Packit Service da4517
Packit Service da4517
	/* if pre_patch_callback or stop_machine failed */
Packit Service da4517
	if (ret) {
Packit Service da4517
		list_for_each_entry(object, &kpmod->objects, list)
Packit Service da4517
			post_unpatch_callback(object);
Packit Service da4517
	}
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service da4517
	 * For the replace case, remove any obsolete funcs from the ftrace
Packit Service da4517
	 * filter, and disable the owning patch module so that it can be
Packit Service da4517
	 * removed.
Packit Service ac8aad
	 */
Packit Service ac8aad
	if (!ret && replace) {
Packit Service ac8aad
		struct kpatch_module *kpmod2, *safe;
Packit Service da4517
		int force;
Packit Service ac8aad
Packit Service da4517
		force = kpatch_ftrace_remove_unpatched_funcs();
Packit Service ac8aad
Packit Service ac8aad
		list_for_each_entry_safe(kpmod2, safe, &kpmod_list, list) {
Packit Service ac8aad
			if (kpmod == kpmod2)
Packit Service ac8aad
				continue;
Packit Service ac8aad
Packit Service ac8aad
			kpmod2->enabled = false;
Packit Service ac8aad
			pr_notice("unloaded patch module '%s'\n",
Packit Service ac8aad
				  kpmod2->mod->name);
Packit Service ac8aad
Packit Service ac8aad
			/*
Packit Service ac8aad
			 * Don't allow modules with forced functions to be
Packit Service ac8aad
			 * removed because they might still be in use.
Packit Service ac8aad
			 */
Packit Service ac8aad
			if (!force)
Packit Service ac8aad
				module_put(kpmod2->mod);
Packit Service ac8aad
Packit Service ac8aad
			list_del(&kpmod2->list);
Packit Service ac8aad
		}
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
Packit Service ac8aad
	/* memory barrier between func hash and state write */
Packit Service ac8aad
	smp_wmb();
Packit Service ac8aad
Packit Service ac8aad
	/* NMI handlers can return to normal now */
Packit Service ac8aad
	kpatch_state_idle();
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service ac8aad
	 * Wait for all existing NMI handlers to complete so that they don't
Packit Service ac8aad
	 * see any changes to funcs or funcs->op that might occur after this
Packit Service ac8aad
	 * point.
Packit Service ac8aad
	 *
Packit Service ac8aad
	 * Any NMI handlers starting after this point will see the IDLE state.
Packit Service ac8aad
	 */
Packit Service ac8aad
	synchronize_rcu();
Packit Service ac8aad
Packit Service ac8aad
	if (ret)
Packit Service ac8aad
		goto err_ops;
Packit Service ac8aad
Packit Service ac8aad
	do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
		func->op = KPATCH_OP_NONE;
Packit Service ac8aad
	} while_for_each_linked_func();
Packit Service ac8aad
Packit Service ac8aad
/* HAS_MODULE_TAINT - upstream 2992ef29ae01 "livepatch/module: make TAINT_LIVEPATCH module-specific" */
Packit Service ac8aad
/* HAS_MODULE_TAINT_LONG - upstream 7fd8329ba502 "taint/module: Clean up global and module taint flags handling" */
Packit Service ac8aad
#ifdef RHEL_RELEASE_CODE
Packit Service ac8aad
# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 4)
Packit Service ac8aad
#  define HAS_MODULE_TAINT
Packit Service ac8aad
# endif
Packit Service ac8aad
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
Packit Service ac8aad
# define HAS_MODULE_TAINT_LONG
Packit Service ac8aad
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
Packit Service ac8aad
# define HAS_MODULE_TAINT
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
#ifdef TAINT_LIVEPATCH
Packit Service ac8aad
	pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n");
Packit Service ac8aad
	add_taint(TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
Packit Service ac8aad
# ifdef HAS_MODULE_TAINT_LONG
Packit Service ac8aad
	set_bit(TAINT_LIVEPATCH, &kpmod->mod->taints);
Packit Service ac8aad
# elif defined(HAS_MODULE_TAINT)
Packit Service ac8aad
	kpmod->mod->taints |= (1 << TAINT_LIVEPATCH);
Packit Service ac8aad
# endif
Packit Service ac8aad
#else
Packit Service ac8aad
	pr_notice_once("tainting kernel with TAINT_USER\n");
Packit Service ac8aad
	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
Packit Service ac8aad
#endif
Packit Service ac8aad
Packit Service ac8aad
	pr_notice("loaded patch module '%s'\n", kpmod->mod->name);
Packit Service ac8aad
Packit Service ac8aad
	kpmod->enabled = true;
Packit Service ac8aad
Packit Service ac8aad
	up(&kpatch_mutex);
Packit Service ac8aad
	return 0;
Packit Service ac8aad
Packit Service ac8aad
err_ops:
Packit Service ac8aad
	if (replace)
Packit Service ac8aad
		hash_for_each_rcu(kpatch_func_hash, i, func, node)
Packit Service ac8aad
			func->op = KPATCH_OP_NONE;
Packit Service ac8aad
err_unlink:
Packit Service ac8aad
	list_for_each_entry(object, &kpmod->objects, list) {
Packit Service ac8aad
		if (object == object_err)
Packit Service ac8aad
			break;
Packit Service ac8aad
		if (!kpatch_object_linked(object))
Packit Service ac8aad
			continue;
Packit Service ac8aad
		WARN_ON(kpatch_unlink_object(object));
Packit Service ac8aad
	}
Packit Service ac8aad
	module_put(kpmod->mod);
Packit Service ac8aad
err_list:
Packit Service ac8aad
	list_del(&kpmod->list);
Packit Service ac8aad
err_up:
Packit Service ac8aad
	up(&kpatch_mutex);
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
EXPORT_SYMBOL(kpatch_register);
Packit Service ac8aad
Packit Service ac8aad
int kpatch_unregister(struct kpatch_module *kpmod)
Packit Service ac8aad
{
Packit Service ac8aad
	struct kpatch_object *object;
Packit Service ac8aad
	struct kpatch_func *func;
Packit Service ac8aad
	int ret, force = 0;
Packit Service ac8aad
Packit Service ac8aad
	down(&kpatch_mutex);
Packit Service ac8aad
Packit Service ac8aad
	if (!kpmod->enabled) {
Packit Service ac8aad
	    ret = -EINVAL;
Packit Service ac8aad
	    goto out;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
		func->op = KPATCH_OP_UNPATCH;
Packit Service ac8aad
		if (func->force)
Packit Service ac8aad
			force = 1;
Packit Service ac8aad
	} while_for_each_linked_func();
Packit Service ac8aad
Packit Service ac8aad
	/* memory barrier between func hash and state write */
Packit Service ac8aad
	smp_wmb();
Packit Service ac8aad
Packit Service ac8aad
	kpatch_state_updating();
Packit Service ac8aad
Packit Service ac8aad
	ret = stop_machine(kpatch_remove_patch, kpmod, NULL);
Packit Service ac8aad
Packit Service da4517
	if (!ret) {
Packit Service da4517
		/* run any user-defined post-unpatch callbacks */
Packit Service da4517
		list_for_each_entry(object, &kpmod->objects, list)
Packit Service da4517
			post_unpatch_callback(object);
Packit Service da4517
	}
Packit Service ac8aad
	/* NMI handlers can return to normal now */
Packit Service ac8aad
	kpatch_state_idle();
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service ac8aad
	 * Wait for all existing NMI handlers to complete so that they don't
Packit Service ac8aad
	 * see any changes to funcs or funcs->op that might occur after this
Packit Service ac8aad
	 * point.
Packit Service ac8aad
	 *
Packit Service ac8aad
	 * Any NMI handlers starting after this point will see the IDLE state.
Packit Service ac8aad
	 */
Packit Service ac8aad
	synchronize_rcu();
Packit Service ac8aad
Packit Service ac8aad
	if (ret) {
Packit Service ac8aad
		do_for_each_linked_func(kpmod, func) {
Packit Service ac8aad
			func->op = KPATCH_OP_NONE;
Packit Service ac8aad
		} while_for_each_linked_func();
Packit Service ac8aad
		goto out;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	list_for_each_entry(object, &kpmod->objects, list) {
Packit Service ac8aad
		if (!kpatch_object_linked(object))
Packit Service ac8aad
			continue;
Packit Service ac8aad
		ret = kpatch_unlink_object(object);
Packit Service ac8aad
		if (ret)
Packit Service ac8aad
			goto out;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	pr_notice("unloaded patch module '%s'\n", kpmod->mod->name);
Packit Service ac8aad
Packit Service ac8aad
	kpmod->enabled = false;
Packit Service ac8aad
Packit Service ac8aad
	/*
Packit Service ac8aad
	 * Don't allow modules with forced functions to be removed because they
Packit Service ac8aad
	 * might still be in use.
Packit Service ac8aad
	 */
Packit Service ac8aad
	if (!force)
Packit Service ac8aad
		module_put(kpmod->mod);
Packit Service ac8aad
Packit Service ac8aad
	list_del(&kpmod->list);
Packit Service ac8aad
Packit Service ac8aad
out:
Packit Service ac8aad
	up(&kpatch_mutex);
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
EXPORT_SYMBOL(kpatch_unregister);
Packit Service ac8aad
Packit Service ac8aad
Packit Service ac8aad
static struct notifier_block kpatch_module_nb_coming = {
Packit Service ac8aad
	.notifier_call = kpatch_module_notify_coming,
Packit Service ac8aad
	.priority = INT_MIN, /* called last */
Packit Service ac8aad
};
Packit Service ac8aad
static struct notifier_block kpatch_module_nb_going = {
Packit Service ac8aad
	.notifier_call = kpatch_module_notify_going,
Packit Service ac8aad
	.priority = INT_MAX, /* called first */
Packit Service ac8aad
};
Packit Service ac8aad
Packit Service ac8aad
static int kpatch_init(void)
Packit Service ac8aad
{
Packit Service ac8aad
	int ret;
Packit Service ac8aad
Packit Service ac8aad
	kpatch_set_memory_rw = (void *)kallsyms_lookup_name("set_memory_rw");
Packit Service ac8aad
	if (!kpatch_set_memory_rw) {
Packit Service ac8aad
		pr_err("can't find set_memory_rw symbol\n");
Packit Service ac8aad
		return -ENXIO;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	kpatch_set_memory_ro = (void *)kallsyms_lookup_name("set_memory_ro");
Packit Service ac8aad
	if (!kpatch_set_memory_ro) {
Packit Service ac8aad
		pr_err("can't find set_memory_ro symbol\n");
Packit Service ac8aad
		return -ENXIO;
Packit Service ac8aad
	}
Packit Service ac8aad
Packit Service ac8aad
	kpatch_root_kobj = kobject_create_and_add("kpatch", kernel_kobj);
Packit Service ac8aad
	if (!kpatch_root_kobj)
Packit Service ac8aad
		return -ENOMEM;
Packit Service ac8aad
Packit Service ac8aad
	ret = register_module_notifier(&kpatch_module_nb_coming);
Packit Service ac8aad
	if (ret)
Packit Service ac8aad
		goto err_root_kobj;
Packit Service ac8aad
	ret = register_module_notifier(&kpatch_module_nb_going);
Packit Service ac8aad
	if (ret)
Packit Service ac8aad
		goto err_unregister_coming;
Packit Service ac8aad
Packit Service ac8aad
	return 0;
Packit Service ac8aad
Packit Service ac8aad
err_unregister_coming:
Packit Service ac8aad
	WARN_ON(unregister_module_notifier(&kpatch_module_nb_coming));
Packit Service ac8aad
err_root_kobj:
Packit Service ac8aad
	kobject_put(kpatch_root_kobj);
Packit Service ac8aad
	return ret;
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
static void kpatch_exit(void)
Packit Service ac8aad
{
Packit Service ac8aad
	rcu_barrier();
Packit Service ac8aad
Packit Service ac8aad
	WARN_ON(kpatch_num_patched != 0);
Packit Service ac8aad
	WARN_ON(unregister_module_notifier(&kpatch_module_nb_coming));
Packit Service ac8aad
	WARN_ON(unregister_module_notifier(&kpatch_module_nb_going));
Packit Service ac8aad
	kobject_put(kpatch_root_kobj);
Packit Service ac8aad
}
Packit Service ac8aad
Packit Service ac8aad
module_init(kpatch_init);
Packit Service ac8aad
module_exit(kpatch_exit);
Packit Service ac8aad
MODULE_LICENSE("GPL");