Re: mlock(1)

From: Chris Wright
Date: Fri Sep 24 2004 - 19:30:19 EST


* Andrew Morton (akpm@xxxxxxxx) wrote:
> Jeff Garzik <jgarzik@xxxxxxxxx> wrote:
> >
> > How feasible is it to create an mlock(1) utility, that would allow
> > priveleged users to execute a daemon such that none of the memory the
> > daemon allocates will ever be swapped out?
>
> It used to be the case that mlockall(MCL_FUTURE) was inherited across fork,
> which would do what you want.
>
> But that was a bug and we fixed it a couple of years back, sadly.
>
> I guess we could add a new mlockall mode which _is_ inherited across fork.

Here's a simple (bit ugly) hack that does it (esp. the exec part).
Seems to miss one page, probably from the arguments or so. Not sure if
it's worth pursuing, but here it is ;-)

$ ./mlock /bin/cat /proc/self/status | grep Vm
VmSize: 3436 kB
VmLck: 3432 kB
VmRSS: 3436 kB
VmData: 144 kB
VmStk: 8 kB
VmExe: 13 kB
VmLib: 1195 kB

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

===== fs/binfmt_elf.c 1.88 vs edited =====
--- 1.88/fs/binfmt_elf.c 2004-09-22 13:34:05 -07:00
+++ edited/fs/binfmt_elf.c 2004-09-24 17:15:53 -07:00
@@ -83,6 +83,9 @@

#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)

+#define MCL_FOREVER 4
+#define PF_MEMLOCK 0x00400000
+
static int set_brk(unsigned long start, unsigned long end)
{
start = ELF_PAGEALIGN(start);
@@ -704,7 +707,7 @@
current->mm->end_code = 0;
current->mm->mmap = NULL;
current->flags &= ~PF_FORKNOEXEC;
- current->mm->def_flags = def_flags;
+ current->mm->def_flags = (current->flags & PF_MEMLOCK) ? VM_LOCKED : 0;

/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
===== mm/mlock.c 1.9 vs edited =====
--- 1.9/mm/mlock.c 2004-08-23 01:15:25 -07:00
+++ edited/mm/mlock.c 2004-09-24 16:07:16 -07:00
@@ -8,6 +8,8 @@
#include <linux/mman.h>
#include <linux/mm.h>

+#define MCL_FOREVER 4
+#define PF_MEMLOCK 0x00400000

static int mlock_fixup(struct vm_area_struct * vma,
unsigned long start, unsigned long end, unsigned int newflags)
@@ -150,6 +152,9 @@
def_flags = VM_LOCKED;
current->mm->def_flags = def_flags;

+ if (flags & MCL_FOREVER)
+ current->flags |= PF_MEMLOCK;
+
error = 0;
for (vma = current->mm->mmap; vma ; vma = vma->vm_next) {
unsigned int newflags;
@@ -170,7 +175,7 @@
int ret = -EINVAL;

down_write(&current->mm->mmap_sem);
- if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
+ if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE | MCL_FOREVER)))
goto out;

lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>

#define MCL_FOREVER 4

int main(int argc, char *argv[], char *envp[])
{
int rc;
int c, do_fork = 0;

while ((c = getopt(argc, argv, "f")) != -1) {
switch(c) {
case 'f':
do_fork = 1;
break;
default:
printf("usage:\t%s [-f] program_to_exec\n", argv[0]);
}
}
argv += optind;

rc = mlockall(MCL_FUTURE|MCL_FOREVER);
if (rc == -1)
perror("mlockall");

if (do_fork) {
int pid = fork();
if (pid > 0)
exit(0);
else if (pid < 0) {
perror("fork");
exit(1);
}
}
execve(argv[0], argv, envp);
perror("execve");
exit(1);
}