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 */ 27static DEFINE_MUTEX(kpid_mutex); 28 29static unsigned int npids, npids_pending; 30static int klp_pids[NR_CPUS]; 31module_param_array(klp_pids, int, &npids_pending, 0); 32MODULE_PARM_DESC(klp_pids, "Array of pids to be transitioned to livepatched state."); 33 34static 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 40static struct kobj_attribute klp_attr = __ATTR_RO(npids); 41static struct kobject *klp_kobj; 42 43static 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 62static struct klp_func vmlinux_funcs[] = { 63 { 64 .old_name = __stringify(FN_PREFIX) "sys_getpid", 65 .new_func = lp_sys_getpid, 66 }, {} 67}; 68 69static struct klp_object objs[] = { 70 { 71 /* name being NULL means vmlinux */ 72 .funcs = vmlinux_funcs, 73 }, {} 74}; 75 76static struct klp_patch patch = { 77 .mod = THIS_MODULE, 78 .objs = objs, 79}; 80 81static 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 104static void livepatch_exit(void) 105{ 106 kobject_put(klp_kobj); 107} 108 109module_init(livepatch_init); 110module_exit(livepatch_exit); 111MODULE_LICENSE("GPL"); 112MODULE_INFO(livepatch, "Y"); 113MODULE_AUTHOR("Libor Pechacek <lpechacek@suse.cz>"); 114MODULE_AUTHOR("Nicolai Stange <nstange@suse.de>"); 115MODULE_AUTHOR("Marcos Paulo de Souza <mpdesouza@suse.com>"); 116MODULE_DESCRIPTION("Livepatch test: syscall transition"); 117