Неожиданное разрешение exec от mmap, когда файлы сборки включены в проект




linux assembly (2)

В Linux есть исполняемый домен READ_IMPLIES_EXEC , 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;
}

Если вы скомпилируете это вместе с пустым файлом .s , вы увидите, что он включен, но без него он будет отключен. Начальное значение этого происходит из метаинформации ELF в вашем двоичном файле . Сделайте readelf -Wl example . Вы увидите эту строку, когда скомпилируете без пустого файла .s :

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

Но этот, когда вы скомпилировали с ним:

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

Обратите внимание на RWE вместо RW . Причина этого в том, что компоновщик предполагает, что ваши файлы сборки требуют read-implies-exec, если явно не указано, что они этого не делают, а если какой-либо части вашей программы требуется read-implies-exec, то он включен для всей вашей программы. , Файлы сборки, которые компилирует GCC, сообщают, что в этом нет необходимости, с этой строкой (вы увидите это, если скомпилируете с -S ):

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

Поместите эту строку в example.s , и она будет указывать компоновщику, что он ему тоже не нужен, и ваша программа будет работать так, как ожидалось.

Я бьюсь головой об стену с этим.

В моем проекте, когда я выделяю память с помощью 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 

В качестве альтернативы для изменения ваших сборочных файлов с помощью GNU-специфичных вариантов директив раздела, вы можете добавить -Wa,--noexecstack в вашу командную строку для построения сборочных файлов. Например, посмотрите, как я это делаю в configure musl:

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

Я полагаю, что по крайней мере некоторые версии clang с интегрированным ассемблером могут требовать, чтобы он был передан как --noexecstack (без -Wa ), поэтому ваш скрипт configure, вероятно, должен проверить оба и увидеть, что принято.

Вы также можете использовать -Wl,-z,noexecstack во время соединения (в LDFLAGS ), чтобы получить тот же результат. Недостаток этого состоит в том, что это не помогает, если ваш проект создает статические ( .a ) файлы библиотеки для использования другим программным обеспечением, так как тогда вы не контролируете параметры времени соединения, когда он используется другими программами.







mmap