【问题标题】:Beginning of stack on LinuxLinux 上的堆栈开始
【发布时间】:2019-02-05 21:51:10
【问题描述】:

我认为我可以通过在 main 中获取变量的地址并向上舍入到页面边界来开始我的进程堆栈(考虑到我的堆栈会增长)。

我将此与/proc/self/maps 报告的边界进行了比较,它总是偏离 1、2 或 3 页(每页 4096 字节),从来没有不同的偏移量。每次运行的差异都会有所不同,以下(杂乱的,不是简约的)管道中使用的这个 C 程序展示了差异。

stacksz.c:

#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#define CAT "cat /proc/XXXXXXXXXXX/maps"
#define CATP "cat /proc/%ld/maps"
#define MASK ((sizeof(char)<<12)-1)

int main()
{
    uintptr_t  top = (uintptr_t)&top + MASK & ~MASK;

    char cat[sizeof CAT];
    sprintf(cat,CATP,(long)getpid());
    if(system(cat)) return 1;

    printf(" %lx stack\n", top);
    return 0;
}

bash 管道:

gcc stacksz.c && echo "$(( $(./a.out |grep stack |tr '-' ' ' |cut -d' ' -f2 |sed 's/^/0x/'|tr '\n' -|sed 's/-$//') ))"

我很好奇是否有人可以解释这种现象。 机器是Linux precision 4.15.0-43-generic #46-Ubuntu SMP x86_64。 ` ( 我在 1000 次运行中得到了以下偏移分布:

4096 195
8192 490
12288 315

)。

【问题讨论】:

  • 你开启了 ASLR 吗?
  • 您是否使用调试器查看过堆栈中的内容?
  • @ASLR 所有地址都会随着每次运行而变化,所以我想是的。
  • (顺便可以用/proc/self/maps。)
  • 哦,在这里,如果你选择一个不同的局部变量,你会得到更多的期望:wandbox.org/permlink/tO5WuOAb3SdCed3v

标签: c linux memory


【解决方案1】:

ASLR 首先完全随机化虚拟内存中的堆栈位置。但它做得更多:它还随机化了相对于堆栈映射顶部的堆栈指针!

来自linux源代码:

unsigned long arch_align_stack(unsigned long sp)
{
        if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
                sp -= get_random_int() % 8192;
        return sp & ~0xf;
}

这里,如果 ASLR 处于活动状态,则堆栈指针减少 0-8192 字节,然后对齐 16 字节。这解释了1-3页的可变偏移量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2011-11-01
    • 2019-09-20
    • 2010-12-20
    • 2014-05-20
    相关资源
    最近更新 更多