cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_klp_state2.c (4797B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2019 SUSE
      3
      4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      5
      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 1
     13/* Version 2 supports migration. */
     14#define CONSOLE_LOGLEVEL_STATE_VERSION 2
     15
     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	else
     29		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");