Динамическое расширение стека Linux - PullRequest
0 голосов
/ 07 февраля 2019

Я заметил, что стек Linux начинается с малого и расширяется с ошибками страниц, вызванными рекурсией / pushes / vlas до размера getrlimit(RLIMIT_STACK,...), Give или Take (по умолчанию 8MiB в моей системе).

Любопытнохотя, если я вызываю сбои страниц, обращаясь к байтам напрямую, в пределах лимита, Linux будет просто регулярно выполнять segfault, не расширяя отображение страниц (хотя, если я делаю это после того, как у меня есть, например, alloca, вызывает расширение стека).

Пример программы:

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#define CMD "grep stack /proc/XXXXXXXXXXXXXXXX/maps"
#define CMDP "grep stack /proc/%ld/maps"
void vla(size_t Sz)
{
    char b[Sz];
    b[0]='y';
    b[1]='\0';
    puts(b);
}
#define OFFSET (sizeof(char)<<12)
int main(int C, char **V)
{
    char cmd[sizeof CMD]; sprintf(cmd,CMDP,(long)getpid());
    if(system(cmd)) return 1;
    for(int i=0; ; i++){
        printf("%d\n", i);
        char *ptr = (char*)(((uintptr_t)&ptr)-i*OFFSET);
        if(C>1) vla(i*OFFSET); //pass an argument to the executable to turn this on
        ptr[0] = 'x';
        ptr[1] = '\0';
        if(system(cmd)) return 1;
        puts(ptr);
    }
}

Какой код ядра делает это?Как это отличает естественный рост стека от того, что я копаюсь в адресном пространстве?

1 Ответ

0 голосов
/ 07 февраля 2019

Ядро Linux принимает содержимое указателя стека в качестве предела (в разумных пределах).При доступе к стеку ниже указатель стека минус 65536, а размер для 32-х беззнаковых длин вызывает нарушение сегментации.Итак, если вы обращаетесь к памяти вниз по стеку, вы должны убедиться, что указатель стека каким-то образом уменьшается с доступом, чтобы ядро ​​linux увеличивало сегмент.Посмотрите этот фрагмент из /arch/x86/mm/fault.c:

if (sw_error_code & X86_PF_USER) {
    /*
     * Accessing the stack below %sp is always a bug.
     * The large cushion allows instructions like enter
     * and pusha to work. ("enter $65535, $31" pushes
     * 32 pointers and then decrements %sp by 65535.)
     */
    if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
        bad_area(regs, sw_error_code, address);
        return;
    }
}

Значение регистра указателя стека является ключевым здесь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...