从包装器中 mlock 程序

Sha*_*rki 1 c linux memory-management

只是一个简单的问题(我希望如此)。如何通过 mlock 分配地址空间,然后在该空间内启动应用程序?

例如,我有一个从配置环境的包装程序启动的二进制文件。我只能访问包装器代码,并且希望在某个地址空间中启动二进制文件。可以从包装器中执行此操作吗?

谢谢!

Nom*_*mal 5

如果您有程序的源代码,请添加命令行选项,以便程序mlockall(MCL_CURRENT | MCL_FUTURE)在某个时刻调用。这会将其锁定在内存中。

如果你想控制内核加载程序的地址空间,你需要深入研究内核内部。最有可能的是,没有理由这样做;只有拥有真正时髦硬件的人才会这样做。

如果您没有源代码,或者不想重新编译程序,那么您可以创建一个执行命令的动态库,并通过LD_PRELOAD.

将以下内容另存为lockall.c

#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>

static void wrerr(const char *p)
{
    if (p) {
        const char *q = p + strlen(p);
        ssize_t     n;

        while (p < q) {
            n = write(STDERR_FILENO, p, (size_t)(q - p));
            if (n > 0)
                p += n;
            else
            if (n != -1 || errno != EINTR)
                return;
        }
    }
}

static void init(void) __attribute__((constructor));
static void init(void)
{
    int saved_errno = errno;

    if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
        const char *errmsg = strerror(errno);
        wrerr("Cannot lock all memory: ");
        wrerr(errmsg);
        wrerr(".\n");
        exit(127);
    } else
        wrerr("All memory locked.\n");

    errno = saved_errno;
}
Run Code Online (Sandbox Code Playgroud)

liblockall.so使用以下命令将其编译为动态库

gcc -Wall -O2 -fPIC -shared lockall.c -Wl,-soname,liblockall.so -o liblockall.so
Run Code Online (Sandbox Code Playgroud)

例如,将库安装在典型的地方

sudo install -o 0 -g 0 -m 0664 liblockall.so /usr/lib/
Run Code Online (Sandbox Code Playgroud)

这样你就可以运行任何二进制文件,并将其锁定到内存中,使用

LD_PRELOAD=liblockall.so binary arguments..
Run Code Online (Sandbox Code Playgroud)

如果您将库安装在其他位置(未在 中列出/etc/ld.so.conf),则需要指定库的路径,例如

LD_PRELOAD=/usr/lib/liblockall.so binary arguments..
Run Code Online (Sandbox Code Playgroud)

Cannot lock all memory: Cannot allocate memory.通常,当以普通用户身份运行命令时,您会看到插入的库打印的消息。(超级用户或 root 通常没有这样的限制。)这是因为出于显而易见的原因,大多数 Linux 发行版都会限制非特权用户可以锁定到内存中的内存量;这就是RLIMIT_MEMLOCK 资源限制。运行ulimit -l以查看当前设置的每个进程资源限制(显然是针对当前用户)。

我建议您为进程可以运行的内存量设置一个合适的限制,ulimit -l 16384如果以超级用户(root)身份运行,则在执行之前运行例如 bash-built-in (将限制设置为 16384*1024 字节,或 16 MiB)。如果进程泄漏内存,而不是使您的机器崩溃(因为它锁定了所有可用内存),SIGSEGV如果超出限制,进程将会死亡(来自 )。也就是说,您将使用以下命令开始您的流程

ulimit -l 16384
LD_PRELOAD=/usr/lib/liblockall.so binary arguments..
Run Code Online (Sandbox Code Playgroud)

如果使用 Bash 或 dash shell。

如果作为专用用户运行,大多数发行版都会使用pam_limits.soPAM 模块“自动”设置资源限制。使用此格式/etc/security/limits.conf在文件或子目录中的文件中列出限制;该项指定每个进程可以锁定的内存量,以 1024 字节为单位。因此,如果您的服务以 user 身份运行,并且您希望允许用户锁定每个进程最多 16 MB = 16384*1024 字节,则将行添加到或中,无论您的 Linux 发行版喜欢/建议哪个。/etc/security/limits.d/memlockmydevmydev - memlock 16384/etc/security/limits.conf/etc/security/limits.d/mydev.conf

在 PAM 之前,shadow-utils用于控制资源限制。memlock资源限制以1024字节为单位指定;将使用设置 16 兆字节的限制M16384。因此,如果使用 Shadow-utils 而不是 PAM,添加行mydev M16384(后跟您希望指定的任何其他限制)应该可以/etc/limits解决问题。