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