75 lines
2.3 KiB
Diff
75 lines
2.3 KiB
Diff
|
|
From: MontanaOS Kernel Team <kernel@montana.quest>
|
||
|
|
Date: Wed, 6 May 2026 00:00:00 +0000
|
||
|
|
Subject: [PATCH] mm: kernel.user_mlock_unrestricted sysctl
|
||
|
|
|
||
|
|
Adds a sysctl that allows unprivileged processes to mlock pages
|
||
|
|
beyond their RLIMIT_MEMLOCK when set to 1.
|
||
|
|
|
||
|
|
This is required for Montana node daemons running in a non-root
|
||
|
|
namespace (Termux or system service running as a dedicated UID
|
||
|
|
without CAP_IPC_LOCK), where the default RLIMIT_MEMLOCK of 64 KB
|
||
|
|
is insufficient to lock the working set of cryptographic secrets.
|
||
|
|
|
||
|
|
Default value is 0, which preserves vanilla kernel behavior. The
|
||
|
|
sysctl is set to 1 by MontanaOS init.rc only after the system
|
||
|
|
finishes early boot and montana_main service class is started.
|
||
|
|
|
||
|
|
Security model: enabling this sysctl allows any unprivileged process
|
||
|
|
to lock arbitrary amounts of memory, which could be used for a
|
||
|
|
denial-of-service attack against other processes on the same system.
|
||
|
|
On a single-purpose appliance device (MontanaOS phone running as a
|
||
|
|
dedicated validator), this is an acceptable trade-off. The sysctl
|
||
|
|
must NOT be enabled on multi-tenant systems.
|
||
|
|
|
||
|
|
Signed-off-by: MontanaOS Kernel Team <kernel@montana.quest>
|
||
|
|
---
|
||
|
|
kernel/sysctl.c | 12 ++++++++++++
|
||
|
|
mm/mlock.c | 6 ++++++
|
||
|
|
2 files changed, 18 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
|
||
|
|
--- a/kernel/sysctl.c
|
||
|
|
+++ b/kernel/sysctl.c
|
||
|
|
@@ -100,6 +100,9 @@ static const int six_hundred_forty_kb = 640 * 1024;
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
+int sysctl_user_mlock_unrestricted;
|
||
|
|
+EXPORT_SYMBOL(sysctl_user_mlock_unrestricted);
|
||
|
|
+
|
||
|
|
#ifdef CONFIG_PERF_EVENTS
|
||
|
|
static const int six_hundred_forty_kb = 640 * 1024;
|
||
|
|
#endif
|
||
|
|
@@ -1850,6 +1853,15 @@ static struct ctl_table kern_table[] = {
|
||
|
|
.proc_handler = proc_dointvec,
|
||
|
|
},
|
||
|
|
#endif
|
||
|
|
+ {
|
||
|
|
+ .procname = "user_mlock_unrestricted",
|
||
|
|
+ .data = &sysctl_user_mlock_unrestricted,
|
||
|
|
+ .maxlen = sizeof(int),
|
||
|
|
+ .mode = 0644,
|
||
|
|
+ .proc_handler = proc_dointvec_minmax,
|
||
|
|
+ .extra1 = SYSCTL_ZERO,
|
||
|
|
+ .extra2 = SYSCTL_ONE,
|
||
|
|
+ },
|
||
|
|
{}
|
||
|
|
};
|
||
|
|
|
||
|
|
diff --git a/mm/mlock.c b/mm/mlock.c
|
||
|
|
--- a/mm/mlock.c
|
||
|
|
+++ b/mm/mlock.c
|
||
|
|
@@ -589,8 +589,14 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla
|
||
|
|
return error;
|
||
|
|
}
|
||
|
|
|
||
|
|
+extern int sysctl_user_mlock_unrestricted;
|
||
|
|
+
|
||
|
|
static int can_do_mlock(void)
|
||
|
|
{
|
||
|
|
+ if (sysctl_user_mlock_unrestricted)
|
||
|
|
+ return 1;
|
||
|
|
if (rlimit(RLIMIT_MEMLOCK) != 0)
|
||
|
|
return 1;
|
||
|
|
if (capable(CAP_IPC_LOCK))
|