399 lines
15 KiB
Diff
399 lines
15 KiB
Diff
From 4eb6615c1498cb8bff76c31e9596b585410f507d Mon Sep 17 00:00:00 2001
|
|
From: Oleksandr Natalenko <oleksandr@natalenko.name>
|
|
Date: Mon, 30 Sep 2024 08:58:38 +0200
|
|
Subject: mm: expose per-process KSM control via syscalls
|
|
|
|
d7597f59d1d3 added a new API to enable per-process KSM control. It
|
|
however uses prctl, which doesn't allow controlling KSM from outside of
|
|
the current process.
|
|
|
|
Hence, expose this API via 3 syscalls: process_ksm_enable,
|
|
process_ksm_disable and process_ksm_status. Given sufficient privileges,
|
|
auto-KSM can be enable by another process.
|
|
|
|
Since these syscalls are not in the upstream kernel, also expose their
|
|
numbers under /sys/kernel/process_ksm so that userspace tooling like
|
|
uksmd knows how to use them.
|
|
|
|
Signed-off-by: Oleksandr Natalenko <oleksandr@natalenko.name>
|
|
---
|
|
arch/alpha/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/arm/tools/syscall.tbl | 3 +
|
|
arch/m68k/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/microblaze/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/mips/kernel/syscalls/syscall_n32.tbl | 3 +
|
|
arch/mips/kernel/syscalls/syscall_n64.tbl | 3 +
|
|
arch/mips/kernel/syscalls/syscall_o32.tbl | 3 +
|
|
arch/parisc/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/powerpc/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/s390/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/sh/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/sparc/kernel/syscalls/syscall.tbl | 3 +
|
|
arch/x86/entry/syscalls/syscall_32.tbl | 3 +
|
|
arch/x86/entry/syscalls/syscall_64.tbl | 3 +
|
|
arch/xtensa/kernel/syscalls/syscall.tbl | 3 +
|
|
include/linux/syscalls.h | 3 +
|
|
include/uapi/asm-generic/unistd.h | 9 +-
|
|
kernel/sys.c | 138 ++++++++++++++++++
|
|
kernel/sys_ni.c | 3 +
|
|
scripts/syscall.tbl | 3 +
|
|
.../arch/powerpc/entry/syscalls/syscall.tbl | 3 +
|
|
.../perf/arch/s390/entry/syscalls/syscall.tbl | 3 +
|
|
22 files changed, 206 insertions(+), 1 deletion(-)
|
|
|
|
--- a/arch/alpha/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
|
|
@@ -502,3 +502,6 @@
|
|
570 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
571 common lsm_list_modules sys_lsm_list_modules
|
|
572 common mseal sys_mseal
|
|
+573 common process_ksm_enable sys_process_ksm_enable
|
|
+574 common process_ksm_disable sys_process_ksm_disable
|
|
+575 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/arm/tools/syscall.tbl
|
|
+++ b/arch/arm/tools/syscall.tbl
|
|
@@ -477,3 +477,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/m68k/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
|
|
@@ -462,3 +462,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
|
|
@@ -468,3 +468,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
|
|
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
|
|
@@ -401,3 +401,6 @@
|
|
460 n32 lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 n32 lsm_list_modules sys_lsm_list_modules
|
|
462 n32 mseal sys_mseal
|
|
+463 n32 process_ksm_enable sys_process_ksm_enable
|
|
+464 n32 process_ksm_disable sys_process_ksm_disable
|
|
+465 n32 process_ksm_status sys_process_ksm_status
|
|
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
|
|
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
|
|
@@ -377,3 +377,6 @@
|
|
460 n64 lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 n64 lsm_list_modules sys_lsm_list_modules
|
|
462 n64 mseal sys_mseal
|
|
+463 n64 process_ksm_enable sys_process_ksm_enable
|
|
+464 n64 process_ksm_disable sys_process_ksm_disable
|
|
+465 n64 process_ksm_status sys_process_ksm_status
|
|
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
|
|
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
|
|
@@ -450,3 +450,6 @@
|
|
460 o32 lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 o32 lsm_list_modules sys_lsm_list_modules
|
|
462 o32 mseal sys_mseal
|
|
+463 o32 process_ksm_enable sys_process_ksm_enable
|
|
+464 o32 process_ksm_disable sys_process_ksm_disable
|
|
+465 o32 process_ksm_status sys_process_ksm_status
|
|
--- a/arch/parisc/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
|
|
@@ -461,3 +461,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
|
|
@@ -553,3 +553,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/s390/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/s390/kernel/syscalls/syscall.tbl
|
|
@@ -465,3 +465,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status sys_process_ksm_status
|
|
--- a/arch/sh/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/sh/kernel/syscalls/syscall.tbl
|
|
@@ -466,3 +466,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/sparc/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
|
|
@@ -508,3 +508,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/arch/x86/entry/syscalls/syscall_32.tbl
|
|
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
|
|
@@ -468,3 +468,6 @@
|
|
460 i386 lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 i386 lsm_list_modules sys_lsm_list_modules
|
|
462 i386 mseal sys_mseal
|
|
+463 i386 process_ksm_enable sys_process_ksm_enable
|
|
+464 i386 process_ksm_disable sys_process_ksm_disable
|
|
+465 i386 process_ksm_status sys_process_ksm_status
|
|
--- a/arch/x86/entry/syscalls/syscall_64.tbl
|
|
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
|
|
@@ -386,6 +386,9 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
|
|
#
|
|
# Due to a historical design error, certain syscalls are numbered differently
|
|
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
|
|
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
|
|
@@ -433,3 +433,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/include/linux/syscalls.h
|
|
+++ b/include/linux/syscalls.h
|
|
@@ -818,6 +818,9 @@ asmlinkage long sys_madvise(unsigned lon
|
|
asmlinkage long sys_process_madvise(int pidfd, const struct iovec __user *vec,
|
|
size_t vlen, int behavior, unsigned int flags);
|
|
asmlinkage long sys_process_mrelease(int pidfd, unsigned int flags);
|
|
+asmlinkage long sys_process_ksm_enable(int pidfd, unsigned int flags);
|
|
+asmlinkage long sys_process_ksm_disable(int pidfd, unsigned int flags);
|
|
+asmlinkage long sys_process_ksm_status(int pidfd, unsigned int flags);
|
|
asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
|
|
unsigned long prot, unsigned long pgoff,
|
|
unsigned long flags);
|
|
--- a/include/uapi/asm-generic/unistd.h
|
|
+++ b/include/uapi/asm-generic/unistd.h
|
|
@@ -841,8 +841,15 @@ __SYSCALL(__NR_lsm_list_modules, sys_lsm
|
|
#define __NR_mseal 462
|
|
__SYSCALL(__NR_mseal, sys_mseal)
|
|
|
|
+#define __NR_process_ksm_enable 463
|
|
+__SYSCALL(__NR_process_ksm_enable, sys_process_ksm_enable)
|
|
+#define __NR_process_ksm_disable 464
|
|
+__SYSCALL(__NR_process_ksm_disable, sys_process_ksm_disable)
|
|
+#define __NR_process_ksm_status 465
|
|
+__SYSCALL(__NR_process_ksm_status, sys_process_ksm_status)
|
|
+
|
|
#undef __NR_syscalls
|
|
-#define __NR_syscalls 463
|
|
+#define __NR_syscalls 466
|
|
|
|
/*
|
|
* 32 bit systems traditionally used different
|
|
--- a/kernel/sys.c
|
|
+++ b/kernel/sys.c
|
|
@@ -2791,6 +2791,144 @@ SYSCALL_DEFINE5(prctl, int, option, unsi
|
|
return error;
|
|
}
|
|
|
|
+#ifdef CONFIG_KSM
|
|
+enum pkc_action {
|
|
+ PKSM_ENABLE = 0,
|
|
+ PKSM_DISABLE,
|
|
+ PKSM_STATUS,
|
|
+};
|
|
+
|
|
+static long do_process_ksm_control(int pidfd, enum pkc_action action)
|
|
+{
|
|
+ long ret;
|
|
+ struct task_struct *task;
|
|
+ struct mm_struct *mm;
|
|
+ unsigned int f_flags;
|
|
+
|
|
+ task = pidfd_get_task(pidfd, &f_flags);
|
|
+ if (IS_ERR(task)) {
|
|
+ ret = PTR_ERR(task);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* Require PTRACE_MODE_READ to avoid leaking ASLR metadata. */
|
|
+ mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
|
|
+ if (IS_ERR_OR_NULL(mm)) {
|
|
+ ret = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH;
|
|
+ goto release_task;
|
|
+ }
|
|
+
|
|
+ /* Require CAP_SYS_NICE for influencing process performance. */
|
|
+ if (!capable(CAP_SYS_NICE)) {
|
|
+ ret = -EPERM;
|
|
+ goto release_mm;
|
|
+ }
|
|
+
|
|
+ if (mmap_write_lock_killable(mm)) {
|
|
+ ret = -EINTR;
|
|
+ goto release_mm;
|
|
+ }
|
|
+
|
|
+ switch (action) {
|
|
+ case PKSM_ENABLE:
|
|
+ ret = ksm_enable_merge_any(mm);
|
|
+ break;
|
|
+ case PKSM_DISABLE:
|
|
+ ret = ksm_disable_merge_any(mm);
|
|
+ break;
|
|
+ case PKSM_STATUS:
|
|
+ ret = !!test_bit(MMF_VM_MERGE_ANY, &mm->flags);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ mmap_write_unlock(mm);
|
|
+
|
|
+release_mm:
|
|
+ mmput(mm);
|
|
+release_task:
|
|
+ put_task_struct(task);
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+#endif /* CONFIG_KSM */
|
|
+
|
|
+SYSCALL_DEFINE2(process_ksm_enable, int, pidfd, unsigned int, flags)
|
|
+{
|
|
+#ifdef CONFIG_KSM
|
|
+ if (flags != 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return do_process_ksm_control(pidfd, PKSM_ENABLE);
|
|
+#else /* CONFIG_KSM */
|
|
+ return -ENOSYS;
|
|
+#endif /* CONFIG_KSM */
|
|
+}
|
|
+
|
|
+SYSCALL_DEFINE2(process_ksm_disable, int, pidfd, unsigned int, flags)
|
|
+{
|
|
+#ifdef CONFIG_KSM
|
|
+ if (flags != 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return do_process_ksm_control(pidfd, PKSM_DISABLE);
|
|
+#else /* CONFIG_KSM */
|
|
+ return -ENOSYS;
|
|
+#endif /* CONFIG_KSM */
|
|
+}
|
|
+
|
|
+SYSCALL_DEFINE2(process_ksm_status, int, pidfd, unsigned int, flags)
|
|
+{
|
|
+#ifdef CONFIG_KSM
|
|
+ if (flags != 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return do_process_ksm_control(pidfd, PKSM_STATUS);
|
|
+#else /* CONFIG_KSM */
|
|
+ return -ENOSYS;
|
|
+#endif /* CONFIG_KSM */
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_KSM
|
|
+static ssize_t process_ksm_enable_show(struct kobject *kobj,
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "%u\n", __NR_process_ksm_enable);
|
|
+}
|
|
+static struct kobj_attribute process_ksm_enable_attr = __ATTR_RO(process_ksm_enable);
|
|
+
|
|
+static ssize_t process_ksm_disable_show(struct kobject *kobj,
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "%u\n", __NR_process_ksm_disable);
|
|
+}
|
|
+static struct kobj_attribute process_ksm_disable_attr = __ATTR_RO(process_ksm_disable);
|
|
+
|
|
+static ssize_t process_ksm_status_show(struct kobject *kobj,
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "%u\n", __NR_process_ksm_status);
|
|
+}
|
|
+static struct kobj_attribute process_ksm_status_attr = __ATTR_RO(process_ksm_status);
|
|
+
|
|
+static struct attribute *process_ksm_sysfs_attrs[] = {
|
|
+ &process_ksm_enable_attr.attr,
|
|
+ &process_ksm_disable_attr.attr,
|
|
+ &process_ksm_status_attr.attr,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+static const struct attribute_group process_ksm_sysfs_attr_group = {
|
|
+ .attrs = process_ksm_sysfs_attrs,
|
|
+ .name = "process_ksm",
|
|
+};
|
|
+
|
|
+static int __init process_ksm_sysfs_init(void)
|
|
+{
|
|
+ return sysfs_create_group(kernel_kobj, &process_ksm_sysfs_attr_group);
|
|
+}
|
|
+subsys_initcall(process_ksm_sysfs_init);
|
|
+#endif /* CONFIG_KSM */
|
|
+
|
|
SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
|
|
struct getcpu_cache __user *, unused)
|
|
{
|
|
--- a/kernel/sys_ni.c
|
|
+++ b/kernel/sys_ni.c
|
|
@@ -186,6 +186,9 @@ COND_SYSCALL(mincore);
|
|
COND_SYSCALL(madvise);
|
|
COND_SYSCALL(process_madvise);
|
|
COND_SYSCALL(process_mrelease);
|
|
+COND_SYSCALL(process_ksm_enable);
|
|
+COND_SYSCALL(process_ksm_disable);
|
|
+COND_SYSCALL(process_ksm_status);
|
|
COND_SYSCALL(remap_file_pages);
|
|
COND_SYSCALL(mbind);
|
|
COND_SYSCALL(get_mempolicy);
|
|
--- a/scripts/syscall.tbl
|
|
+++ b/scripts/syscall.tbl
|
|
@@ -403,3 +403,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
|
|
+++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
|
|
@@ -553,3 +553,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status
|
|
--- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl
|
|
+++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
|
|
@@ -465,3 +465,6 @@
|
|
460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
|
|
461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules
|
|
462 common mseal sys_mseal sys_mseal
|
|
+463 common process_ksm_enable sys_process_ksm_enable sys_process_ksm_enable
|
|
+464 common process_ksm_disable sys_process_ksm_disable sys_process_ksm_disable
|
|
+465 common process_ksm_status sys_process_ksm_status sys_process_ksm_status
|