brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · c978ea4 Raw
192 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2019 SUSE3 4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt5 6#include <linux/slab.h>7#include <linux/module.h>8#include <linux/kernel.h>9#include <linux/printk.h>10#include <linux/livepatch.h>11 12#define CONSOLE_LOGLEVEL_STATE 113/* Version 2 supports migration. */14#define CONSOLE_LOGLEVEL_STATE_VERSION 215 16static const char *const module_state[] = {17	[MODULE_STATE_LIVE]	= "[MODULE_STATE_LIVE] Normal state",18	[MODULE_STATE_COMING]	= "[MODULE_STATE_COMING] Full formed, running module_init",19	[MODULE_STATE_GOING]	= "[MODULE_STATE_GOING] Going away",20	[MODULE_STATE_UNFORMED]	= "[MODULE_STATE_UNFORMED] Still setting it up",21};22 23static void callback_info(const char *callback, struct klp_object *obj)24{25	if (obj->mod)26		pr_info("%s: %s -> %s\n", callback, obj->mod->name,27			module_state[obj->mod->state]);28	else29		pr_info("%s: vmlinux\n", callback);30}31 32static struct klp_patch patch;33 34static int allocate_loglevel_state(void)35{36	struct klp_state *loglevel_state, *prev_loglevel_state;37 38	prev_loglevel_state = klp_get_prev_state(CONSOLE_LOGLEVEL_STATE);39	if (prev_loglevel_state) {40		pr_info("%s: space to store console_loglevel already allocated\n",41		__func__);42		return 0;43	}44 45	loglevel_state = klp_get_state(&patch, CONSOLE_LOGLEVEL_STATE);46	if (!loglevel_state)47		return -EINVAL;48 49	loglevel_state->data = kzalloc(sizeof(console_loglevel), GFP_KERNEL);50	if (!loglevel_state->data)51		return -ENOMEM;52 53	pr_info("%s: allocating space to store console_loglevel\n",54		__func__);55	return 0;56}57 58static void fix_console_loglevel(void)59{60	struct klp_state *loglevel_state, *prev_loglevel_state;61 62	loglevel_state = klp_get_state(&patch, CONSOLE_LOGLEVEL_STATE);63	if (!loglevel_state)64		return;65 66	prev_loglevel_state = klp_get_prev_state(CONSOLE_LOGLEVEL_STATE);67	if (prev_loglevel_state) {68		pr_info("%s: taking over the console_loglevel change\n",69		__func__);70		loglevel_state->data = prev_loglevel_state->data;71		return;72	}73 74	pr_info("%s: fixing console_loglevel\n", __func__);75	*(int *)loglevel_state->data = console_loglevel;76	console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;77}78 79static void restore_console_loglevel(void)80{81	struct klp_state *loglevel_state, *prev_loglevel_state;82 83	prev_loglevel_state = klp_get_prev_state(CONSOLE_LOGLEVEL_STATE);84	if (prev_loglevel_state) {85		pr_info("%s: passing the console_loglevel change back to the old livepatch\n",86		__func__);87		return;88	}89 90	loglevel_state = klp_get_state(&patch, CONSOLE_LOGLEVEL_STATE);91	if (!loglevel_state)92		return;93 94	pr_info("%s: restoring console_loglevel\n", __func__);95	console_loglevel = *(int *)loglevel_state->data;96}97 98static void free_loglevel_state(void)99{100	struct klp_state *loglevel_state, *prev_loglevel_state;101 102	prev_loglevel_state = klp_get_prev_state(CONSOLE_LOGLEVEL_STATE);103	if (prev_loglevel_state) {104		pr_info("%s: keeping space to store console_loglevel\n",105		__func__);106		return;107	}108 109	loglevel_state = klp_get_state(&patch, CONSOLE_LOGLEVEL_STATE);110	if (!loglevel_state)111		return;112 113	pr_info("%s: freeing space for the stored console_loglevel\n",114		__func__);115	kfree(loglevel_state->data);116}117 118/* Executed on object patching (ie, patch enablement) */119static int pre_patch_callback(struct klp_object *obj)120{121	callback_info(__func__, obj);122	return allocate_loglevel_state();123}124 125/* Executed on object unpatching (ie, patch disablement) */126static void post_patch_callback(struct klp_object *obj)127{128	callback_info(__func__, obj);129	fix_console_loglevel();130}131 132/* Executed on object unpatching (ie, patch disablement) */133static void pre_unpatch_callback(struct klp_object *obj)134{135	callback_info(__func__, obj);136	restore_console_loglevel();137}138 139/* Executed on object unpatching (ie, patch disablement) */140static void post_unpatch_callback(struct klp_object *obj)141{142	callback_info(__func__, obj);143	free_loglevel_state();144}145 146static struct klp_func no_funcs[] = {147	{}148};149 150static struct klp_object objs[] = {151	{152		.name = NULL,	/* vmlinux */153		.funcs = no_funcs,154		.callbacks = {155			.pre_patch = pre_patch_callback,156			.post_patch = post_patch_callback,157			.pre_unpatch = pre_unpatch_callback,158			.post_unpatch = post_unpatch_callback,159		},160	}, { }161};162 163static struct klp_state states[] = {164	{165		.id = CONSOLE_LOGLEVEL_STATE,166		.version = CONSOLE_LOGLEVEL_STATE_VERSION,167	}, { }168};169 170static struct klp_patch patch = {171	.mod = THIS_MODULE,172	.objs = objs,173	.states = states,174	.replace = true,175};176 177static int test_klp_callbacks_demo_init(void)178{179	return klp_enable_patch(&patch);180}181 182static void test_klp_callbacks_demo_exit(void)183{184}185 186module_init(test_klp_callbacks_demo_init);187module_exit(test_klp_callbacks_demo_exit);188MODULE_LICENSE("GPL");189MODULE_INFO(livepatch, "Y");190MODULE_AUTHOR("Petr Mladek <pmladek@suse.com>");191MODULE_DESCRIPTION("Livepatch test: system state modification");192