是否可以更新现有内存映射的标志?

发布于 2025-02-12 16:33:40 字数 497 浏览 1 评论 0原文

我正在编写X64组件中的一个小程序,该程序将产生孩子,所有这些都共享他们的内存映射,以便他们可以修改彼此的代码。为此,由于sys_clone的参数clone_vm似乎将程序置于未定义的行为中,因此我计划使用mmap's map_shared参数。

但是,我还需要孩子们修改父亲的守则。一种选择是还分配map_shared映射并将其交给父亲,但是如果可能的话,我想避免这种情况(仅出于优雅的原因)。

由于该程序的基本映射(0x400000一个在64位linux上)将不具有map_shared flag默认情况下,是否可以使用SYSCALL将其更新为设置此标志? munmap然后mmap将不做并引起sigsegv,而mprotect只能更改RWX权限。

I am writing a small program in x64 assembly that will spawn children, all sharing their memory mappings so they can modify each other's code. For this, since the argument CLONE_VM of sys_clone seems to place the program into undefined behaviour, I plan to use mmap's MAP_SHARED argument.

However, I would also need the children to modify the code of the father. One option is to also allocate a MAP_SHARED mapping and give it to the father, but I'd like to avoid this if possible (only for elegance reasons).

Since the base mapping (the 0x400000 one on 64-bits Linux) of the program will not have the MAP_SHARED flag by default, is it possible to update it using a syscall to set this flag? munmap then mmap will not do and cause a SIGSEGV, and mprotect can only change the RWX permissions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暮倦 2025-02-19 16:33:40

您无法更改现有的映射是私有的还是共享的,但是您可以在现有的私有映射上映射新的共享映射。您甚至可以在C中这样做:

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

int main(void) {
    FILE *stream = fopen("/proc/self/maps", "rb");
    if(!stream) {
        perror("fopen");
        return 1;
    }
    char *text_start, *text_end;
    do {
        if(fscanf(stream, " %p-%p%*[^\n]", &text_start, &text_end) != 2) {
            perror("scanf");
            return 1;
        }
    } while(!(text_start <= main && main < text_end));
    if(fclose(stream)) {
        perror("fclose");
        return 1;
    }
    size_t text_len = text_end - text_start;
    char *mem = mmap(NULL, text_len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    if(mem == MAP_FAILED) {
        perror("mmap");
        return 1;
    }
    memcpy(mem, text_start, text_len);
    __builtin___clear_cache(mem, mem + text_len);
    if(mremap(mem, text_len, text_len, MREMAP_MAYMOVE|MREMAP_FIXED, text_start) == MAP_FAILED) {
        perror("mremap");
        return 1;
    }
    /* you can check /proc/PID/maps now to see the new mapping */
    getchar();
}

作为奖励,此程序支持ASLR,并且不需要文本部分以0x400000开始。

You can't change whether an existing mapping is private or shared, but you can map a new shared mapping over an existing private mapping. You can even do so in C, like this:

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

int main(void) {
    FILE *stream = fopen("/proc/self/maps", "rb");
    if(!stream) {
        perror("fopen");
        return 1;
    }
    char *text_start, *text_end;
    do {
        if(fscanf(stream, " %p-%p%*[^\n]", &text_start, &text_end) != 2) {
            perror("scanf");
            return 1;
        }
    } while(!(text_start <= main && main < text_end));
    if(fclose(stream)) {
        perror("fclose");
        return 1;
    }
    size_t text_len = text_end - text_start;
    char *mem = mmap(NULL, text_len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    if(mem == MAP_FAILED) {
        perror("mmap");
        return 1;
    }
    memcpy(mem, text_start, text_len);
    __builtin___clear_cache(mem, mem + text_len);
    if(mremap(mem, text_len, text_len, MREMAP_MAYMOVE|MREMAP_FIXED, text_start) == MAP_FAILED) {
        perror("mremap");
        return 1;
    }
    /* you can check /proc/PID/maps now to see the new mapping */
    getchar();
}

As a bonus, this program supports ASLR and doesn't require that the text section start at 0x400000.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文