1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017-2023 SUSE
* Authors: Libor Pechacek <lpechacek@suse.cz>
* Nicolai Stange <nstange@suse.de>
* Marcos Paulo de Souza <mpdesouza@suse.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/livepatch.h>
/*
* Before CONFIG_ARCH_HAS_SYSCALL_WRAPPER was introduced there were no
* prefixes for system calls.
* powerpc set this config based on configs, so it can be enabled or not.
*/
#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER)
#if defined(__x86_64__)
#define FN_PREFIX __x64_
#elif defined(__s390x__)
#define FN_PREFIX __s390x_
#elif defined(__aarch64__)
#define FN_PREFIX __arm64_
#elif defined(__powerpc__)
#define FN_PREFIX
#else
#error "Missing syscall wrapper for the given architecture."
#endif
#else
/* Do not set a prefix for architectures that do not enable wrappers. */
#define FN_PREFIX
#endif
/* Protects klp_pids */
static DEFINE_MUTEX(kpid_mutex);
static unsigned int npids, npids_pending;
static int klp_pids[NR_CPUS];
module_param_array(klp_pids, int, &npids_pending, 0);
MODULE_PARM_DESC(klp_pids, "Array of pids to be transitioned to livepatched state.");
static ssize_t npids_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%u\n", npids_pending);
}
static struct kobj_attribute klp_attr = __ATTR_RO(npids);
static struct kobject *klp_kobj;
static asmlinkage long lp_sys_getpid(void)
{
int i;
mutex_lock(&kpid_mutex);
if (npids_pending > 0) {
for (i = 0; i < npids; i++) {
if (current->pid == klp_pids[i]) {
klp_pids[i] = 0;
npids_pending--;
break;
}
}
}
mutex_unlock(&kpid_mutex);
return task_tgid_vnr(current);
}
static struct klp_func vmlinux_funcs[] = {
{
.old_name = __stringify(FN_PREFIX) "sys_getpid",
.new_func = lp_sys_getpid,
}, {}
};
static struct klp_object objs[] = {
{
/* name being NULL means vmlinux */
.funcs = vmlinux_funcs,
}, {}
};
static struct klp_patch patch = {
.mod = THIS_MODULE,
.objs = objs,
};
static int livepatch_init(void)
{
int ret;
klp_kobj = kobject_create_and_add("test_klp_syscall", kernel_kobj);
if (!klp_kobj)
return -ENOMEM;
ret = sysfs_create_file(klp_kobj, &klp_attr.attr);
if (ret) {
kobject_put(klp_kobj);
return ret;
}
/*
* Save the number pids to transition to livepatched state before the
* number of pending pids is decremented.
*/
npids = npids_pending;
ret = klp_enable_patch(&patch);
if (ret)
kobject_put(klp_kobj);
return ret;
}
static void livepatch_exit(void)
{
kobject_put(klp_kobj);
}
module_init(livepatch_init);
module_exit(livepatch_exit);
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
MODULE_AUTHOR("Libor Pechacek <lpechacek@suse.cz>");
MODULE_AUTHOR("Nicolai Stange <nstange@suse.de>");
MODULE_AUTHOR("Marcos Paulo de Souza <mpdesouza@suse.com>");
MODULE_DESCRIPTION("Livepatch test: syscall transition");
|