131 lines · 2.9 KB · C
RawDownload
// 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> /* * Before CONFIG_ARCH_HAS_SYSCALL_WRAPPER was introduced there were no * prefixes for system calls. * powerpc set this config based on configs, so it can be enabled or not. */#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER)  #if defined(__x86_64__)    #define FN_PREFIX __x64_  #elif defined(__s390x__)    #define FN_PREFIX __s390x_  #elif defined(__aarch64__)    #define FN_PREFIX __arm64_  #elif defined(__powerpc__)    #define FN_PREFIX  #else    #error "Missing syscall wrapper for the given architecture."  #endif#else  /* Do not set a prefix for architectures that do not enable wrappers. */  #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; 	ret = klp_enable_patch(&patch);	if (ret)		kobject_put(klp_kobj); 	return ret;} 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");