projects/linux·blob master · refs

131 lines · 2.9 KiB

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