static bool klp_initialized(void)
{
-- return klp_root_kobj;
++ return !!klp_root_kobj;
}
struct klp_find_arg {
.count = 0
};
++ mutex_lock(&module_mutex);
kallsyms_on_each_symbol(klp_find_callback, &args);
++ mutex_unlock(&module_mutex);
if (args.count == 0)
pr_err("symbol '%s' not found in symbol table\n", name);
.name = name,
.addr = addr,
};
++ int ret;
-- if (kallsyms_on_each_symbol(klp_verify_callback, &args))
-- return 0;
++ mutex_lock(&module_mutex);
++ ret = kallsyms_on_each_symbol(klp_verify_callback, &args);
++ mutex_unlock(&module_mutex);
-- pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
-- name, addr);
-- return -EINVAL;
++ if (!ret) {
++ pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
++ name, addr);
++ return -EINVAL;
++ }
++
++ return 0;
}
static int klp_find_verify_func_addr(struct klp_object *obj,
int ret;
#if defined(CONFIG_RANDOMIZE_BASE)
- - /* KASLR is enabled, disregard old_addr from user */
- - func->old_addr = 0;
+ + /* If KASLR has been enabled, adjust old_addr accordingly */
+ + if (kaslr_enabled() && func->old_addr)
+ + func->old_addr += kaslr_offset();
#endif
if (!func->old_addr || klp_is_module(obj))
{
struct klp_func *func;
-- for (func = obj->funcs; func->old_name; func++)
++ klp_for_each_func(obj, func)
if (func->state == KLP_ENABLED)
klp_disable_func(func);
if (WARN_ON(!klp_is_object_loaded(obj)))
return -EINVAL;
-- for (func = obj->funcs; func->old_name; func++) {
++ klp_for_each_func(obj, func) {
ret = klp_enable_func(func);
if (ret) {
klp_disable_object(obj);
pr_notice("disabling patch '%s'\n", patch->mod->name);
-- for (obj = patch->objs; obj->funcs; obj++) {
++ klp_for_each_object(patch, obj) {
if (obj->state == KLP_ENABLED)
klp_disable_object(obj);
}
pr_notice("enabling patch '%s'\n", patch->mod->name);
-- for (obj = patch->objs; obj->funcs; obj++) {
++ klp_for_each_object(patch, obj) {
if (!klp_is_object_loaded(obj))
continue;
.default_attrs = klp_patch_attrs,
};
++ static void klp_kobj_release_object(struct kobject *kobj)
++ {
++ }
++
++ static struct kobj_type klp_ktype_object = {
++ .release = klp_kobj_release_object,
++ .sysfs_ops = &kobj_sysfs_ops,
++ };
++
static void klp_kobj_release_func(struct kobject *kobj)
{
}
obj->mod = NULL;
-- for (func = obj->funcs; func->old_name; func++)
++ klp_for_each_func(obj, func)
func->old_addr = 0;
}
for (obj = patch->objs; obj->funcs && obj != limit; obj++) {
klp_free_funcs_limited(obj, NULL);
-- kobject_put(obj->kobj);
++ kobject_put(&obj->kobj);
}
}
func->state = KLP_DISABLED;
return kobject_init_and_add(&func->kobj, &klp_ktype_func,
-- obj->kobj, "%s", func->old_name);
++ &obj->kobj, "%s", func->old_name);
}
/* parts of the initialization that is done only when the object is loaded */
return ret;
}
-- for (func = obj->funcs; func->old_name; func++) {
++ klp_for_each_func(obj, func) {
ret = klp_find_verify_func_addr(obj, func);
if (ret)
return ret;
klp_find_object_module(obj);
name = klp_is_module(obj) ? obj->name : "vmlinux";
-- obj->kobj = kobject_create_and_add(name, &patch->kobj);
-- if (!obj->kobj)
-- return -ENOMEM;
++ ret = kobject_init_and_add(&obj->kobj, &klp_ktype_object,
++ &patch->kobj, "%s", name);
++ if (ret)
++ return ret;
-- for (func = obj->funcs; func->old_name; func++) {
++ klp_for_each_func(obj, func) {
ret = klp_init_func(obj, func);
if (ret)
goto free;
free:
klp_free_funcs_limited(obj, func);
-- kobject_put(obj->kobj);
++ kobject_put(&obj->kobj);
return ret;
}
if (ret)
goto unlock;
-- for (obj = patch->objs; obj->funcs; obj++) {
++ klp_for_each_object(patch, obj) {
ret = klp_init_object(patch, obj);
if (ret)
goto free;
}
EXPORT_SYMBOL_GPL(klp_register_patch);
-- static void klp_module_notify_coming(struct klp_patch *patch,
++ static int klp_module_notify_coming(struct klp_patch *patch,
struct klp_object *obj)
{
struct module *pmod = patch->mod;
int ret;
ret = klp_init_object_loaded(patch, obj);
-- if (ret)
-- goto err;
++ if (ret) {
++ pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n",
++ pmod->name, mod->name, ret);
++ return ret;
++ }
if (patch->state == KLP_DISABLED)
-- return;
++ return 0;
pr_notice("applying patch '%s' to loading module '%s'\n",
pmod->name, mod->name);
ret = klp_enable_object(obj);
-- if (!ret)
-- return;
--
-- err:
-- pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
-- pmod->name, mod->name, ret);
++ if (ret)
++ pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
++ pmod->name, mod->name, ret);
++ return ret;
}
static void klp_module_notify_going(struct klp_patch *patch,
static int klp_module_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
++ int ret;
struct module *mod = data;
struct klp_patch *patch;
struct klp_object *obj;
mod->klp_alive = false;
list_for_each_entry(patch, &klp_patches, list) {
-- for (obj = patch->objs; obj->funcs; obj++) {
++ klp_for_each_object(patch, obj) {
if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
continue;
if (action == MODULE_STATE_COMING) {
obj->mod = mod;
-- klp_module_notify_coming(patch, obj);
++ ret = klp_module_notify_coming(patch, obj);
++ if (ret) {
++ obj->mod = NULL;
++ pr_warn("patch '%s' is in an inconsistent state!\n",
++ patch->mod->name);
++ }
} else /* MODULE_STATE_GOING */
klp_module_notify_going(patch, obj);
.priority = INT_MIN+1, /* called late but before ftrace notifier */
};
-- static int klp_init(void)
++ static int __init klp_init(void)
{
int ret;