mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-31 06:14:39 +01:00
In livepatch_init(), if klp_enable_patch() fails, the previously created kobject and sysfs file are never cleaned up, causing a resource leak. Capture the return value and add proper cleanup on the error path. Signed-off-by: Rui Qi <[email protected]> Acked-by: Miroslav Benes <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Petr Mladek <[email protected]>
132 lines
2.9 KiB
C
132 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2017-2023 SUSE
|
|
* Authors: Libor Pechacek <[email protected]>
|
|
* Nicolai Stange <[email protected]>
|
|
* Marcos Paulo de Souza <[email protected]>
|
|
*/
|
|
|
|
#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 <[email protected]>");
|
|
MODULE_AUTHOR("Nicolai Stange <[email protected]>");
|
|
MODULE_AUTHOR("Marcos Paulo de Souza <[email protected]>");
|
|
MODULE_DESCRIPTION("Livepatch test: syscall transition");
|