Loading...
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 | // 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> #if defined(__x86_64__) #define FN_PREFIX __x64_ #elif defined(__s390x__) #define FN_PREFIX __s390x_ #elif defined(__aarch64__) #define FN_PREFIX __arm64_ #else /* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER */ #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; return klp_enable_patch(&patch); } 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"); |