IT Share you

프로젝트에 어셈블리 파일이 포함 된 경우 잘못된 mmap 동작

shareyou 2020. 12. 8. 20:24
반응형

프로젝트에 어셈블리 파일이 포함 된 경우 잘못된 mmap 동작


나는 이것으로 내 머리를 벽에 두 드린다.

내 프로젝트 mmap에서 매핑 ( /proc/self/maps)을 사용 하여 메모리를 할당 할 때 읽을 수있는 메모리 만 요청 했음에도 불구하고 읽을 수 있고 실행 가능한 영역임을 보여줍니다 .

strace (좋아 보였습니다) 및 기타 디버깅을 조사한 후,이 이상한 문제를 피하는 것처럼 보이는 유일한 방법을 식별 할 수있었습니다. 프로젝트에서 어셈블리 파일을 제거하고 순수한 C 만 남겨 둡니다. (뭐?!)

그래서 여기 이상한 예가 있습니다. 저는 Ubunbtu 19.04 및 기본 gcc에서 작업하고 있습니다.

ASM 파일 (비어 있음)로 대상 실행 파일을 컴파일하면 mmap읽을 수 있고 실행 가능한 영역이 반환되고, 그렇지 않은 경우 빌드하면 올바르게 작동합니다. /proc/self/maps내 예제에 포함 된 출력을 참조하십시오 .

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;
}

example.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 

리눅스는이 실행 도메인 이라고 READ_IMPLIES_EXEC할당 모든 페이지 원인 PROT_READ도 주어질를 PROT_EXEC. 이 프로그램은 자체적으로 활성화되었는지 여부를 보여줍니다.

#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;
}

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

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

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.


As an alternative to modifying your assembly files with GNU-specific section directive variants, you can add -Wa,--noexecstack to your command line for building assembly files. For example, see how I do it in musl's configure:

https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a

I believe at least some versions of clang with integrated-assembler may require it to be passed as --noexecstack (without the -Wa), so your configure script should probably check both and see which is accepted.

You can also use -Wl,-z,noexecstack at link time (in LDFLAGS) to get the same result. The disadvantage of this is that it doesn't help if your project produces static (.a) library files for use by other software, since you then don't control the link-time options when it's used by other programs.

참고URL : https://stackoverflow.com/questions/58260465/incorrect-mmap-behavior-when-assembly-files-included-in-the-project

반응형