Permissão de execução inesperada do mmap quando arquivos de montagem incluídos no projeto




linux assembly (2)

Estou batendo minha cabeça na parede com isso.

No meu projeto, quando estou alocando memória com o mmap o mapeamento ( /proc/self/maps ) mostra que é uma região legível e executável, apesar de solicitar apenas memória legível.

Depois de analisar o strace (que estava com boa aparência) e outras depurações, consegui identificar a única coisa que parece evitar esse problema estranho: remover arquivos de montagem do projeto e deixar apenas C. puro (o que ?!)

Então, aqui está o meu exemplo estranho, estou trabalhando no Ubunbtu 19.04 e no padrão gcc.

Se você compilar o executável de destino com o arquivo ASM (que está vazio), o mmap retornará uma região legível e executável, se você criar sem, ele se comportará corretamente. Veja a saída de /proc/self/maps que eu incorporei no meu exemplo.

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 : é um arquivo vazio!

Saídas

Com a versão incluída do ASM

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

Sem a versão incluída do ASM

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

Como uma alternativa para modificar seus arquivos de montagem com as variantes de diretiva de seção específicas do GNU, você pode adicionar -Wa,--noexecstack à sua linha de comando para criar arquivos de montagem. Por exemplo, veja como eu faço isso no configure do musl:

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

Acredito que pelo menos algumas versões do clang com o assembler-assembler podem exigir que ele seja passado como --noexecstack (sem o -Wa ); portanto, seu script de configuração provavelmente deve verificar os dois e ver o que é aceito.

Você também pode usar -Wl,-z,noexecstack no tempo do link (no LDFLAGS ) para obter o mesmo resultado. A desvantagem disso é que não ajuda se o seu projeto produz arquivos de biblioteca estáticos ( .a ) para uso por outro software, pois você não controla as opções de tempo do link quando usadas por outros programas.


O Linux possui um domínio de execução chamado READ_IMPLIES_EXEC , que faz com que todas as páginas alocadas com PROT_READ também recebam PROT_EXEC . Este programa mostra se está habilitado para si:

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

Se você compilar isso junto com um arquivo .s vazio, verá que ele está ativado, mas sem um, ele será desativado. O valor inicial disso vem das meta-informações ELF no seu binário . readelf -Wl example . Você verá esta linha quando compilar sem o arquivo .s vazio:

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

Mas este quando você compilou:

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

Observe RWE vez de apenas RW . A razão para isso é que o vinculador pressupõe que seus arquivos de montagem requerem leitura implícita-exec, a menos que seja explicitamente informado que não o fazem, e se alguma parte do seu programa exigir leitura implícita-exec, ele será ativado para todo o programa . Os arquivos de montagem que o GCC compila informam que não precisa disso, com esta linha (você verá isso se compilar com -S ):

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

Coloque essa linha em example.s , e servirá para informar ao vinculador que ele também não precisa, e seu programa funcionará conforme o esperado.





mmap