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