当项目中包含程序集文件时,mmap出现意外的exec权限 [英] Unexpected exec permission from mmap when assembly files included in the project

查看:117
本文介绍了当项目中包含程序集文件时,mmap出现意外的exec权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用这个把我的头撞到墙上.

I am banging my head into the wall with this.

在我的项目中,当我使用mmap分配内存时,映射(/proc/self/maps)显示它是一个可读且可执行的区域,尽管,我只请求了可读内存.

In my project, when I'm allocating memory with mmap the mapping (/proc/self/maps) shows that it is an readable and executable region despite I requested only readable memory.

研究了strace(看起来不错)和其他调试之后,我能够确定似乎唯一可以避免这个奇怪问题的东西:从项目中删除程序集文件,只保留纯C.(什么?!)

After looking into strace (which was looking good) and other debugging, I was able to identify the only thing that seems to avoid this strange problem: removing assembly files from the project and leaving only pure C. (what?!)

所以这是我一个奇怪的例子,我正在研究Ubunbtu 19.04和默认gcc.

So here is my strange example, I am working on Ubunbtu 19.04 and default gcc.

如果使用ASM文件(为空)编译目标可执行文件,则mmap返回一个可读且可执行的区域,如果不进行编译则其行为正确.请参见示例中嵌入的/proc/self/maps的输出.

If you compile the target executable with the ASM file (which is empty) then mmap returns a readable and executable region, if you build without then it behave correctly. See the output of /proc/self/maps which I have embedded in my example.

示例.c

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

int main()
{
    void* p;
    p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);

    {
        FILE *f;
        char line[512], s_search[17];
        snprintf(s_search,16,"%lx",(long)p);
        f = fopen("/proc/self/maps","r");
        while (fgets(line,512,f))
        {
            if (strstr(line,s_search)) fputs(line,stderr);
        }

        fclose(f);
    }

    return 0;
}

示例.s :是一个空文件!

输出

包含ASM版本

VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0 

没有包含ASM的版本

VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 r--p 00000000 00:00 0 

推荐答案

Linux具有

Linux has an execution domain called READ_IMPLIES_EXEC, which causes all pages allocated with PROT_READ to also be given PROT_EXEC. This program will show you whether that's enabled for itself:

#include <stdio.h>
#include <sys/personality.h>

int main(void) {
    printf("Read-implies-exec is %s\n", personality(0xffffffff) & READ_IMPLIES_EXEC ? "true" : "false");
    return 0;
}

如果将其与一个空的.s文件一起编译,则会看到该文件已启用,但没有文件,则将其禁用.此

If you compile that along with an empty .s file, you'll see that it's enabled, but without one, it'll be disabled. The initial value of this comes from the ELF meta-information in your binary. Do readelf -Wl example. You'll see this line when you compiled without the empty .s file:

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

但是,当您使用它编译时:

But this one when you compiled with it:

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

请注意RWE,而不仅仅是RW.这样做的原因是,链接器假定您的程序集文件需要read-implies-exec,除非明确告知它们不需要,并且如果程序的任何部分都需要read-implies-exec,那么它将为您的整个程序启用. GCC编译的汇编文件告诉它不需要此行(在此行中,如果使用-S进行编译,您将看到此文件):

Note RWE instead of just RW. The reason for this is that the linker assumes that your assembly files require read-implies-exec unless it's explicitly told that they don't, and if any part of your program requires read-implies-exec, then it's enabled for your whole program. The assembly files that GCC compiles tell it that it doesn't need this, with this line (you'll see this if you compile with -S):

        .section        .note.GNU-stack,"",@progbits

将该行放入example.s中,它将用于告诉链接器它也不需要它,然后您的程序将按预期运行.

Put that line in example.s, and it will serve to tell the linker that it doesn't need it either, and your program will then work as expected.

这篇关于当项目中包含程序集文件时,mmap出现意外的exec权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆