【问题标题】:Heap-Overflow or Buffer-Overflow?堆溢出还是缓冲区溢出?
【发布时间】:2020-01-09 12:36:09
【问题描述】:

这段代码在 memset 上写了一个额外的字符,但是为什么?

int main(int argc, char ∗argv[]) {

    char ∗a, ∗b;
    a=(char ∗)malloc(12);
    b=(char ∗)malloc(12);

    if(!a || !b)
        err(2, "malloc error.\\n");

    bzero(a, 12); bzero(b, 12);
    printf("%x %x (%i)\n", a, b, b−a); // b−a is d.
    memset(a, (int)'a', 11);
    memset(b, (int)'b', 11);
    printf("a: %s\n", a);
    printf("b: %s\n", b);
    printf("−−−\n");
    memset(a, (int)'a', b−a); // Heap−Overflow? Is this happening here ?
    printf("a: %s\n", a);

    free(a);
    free(b);
    return 0;
}

漏洞? 万一这将是一个密码,每次打印后都会有一个额外的字符?

【问题讨论】:

  • 不是 "'。你觉得b−a的结果是什么?
  • 不相关指针(如您的示例中的ab)之间的IIRC 算术是未定义的行为。
  • 另请注意,要打印 (void *) 指针,您应该使用 %p 格式说明符。指针减法的结果是(IIRC)一个size_t,应该用%zu打印。格式说明符和参数类型不匹配会导致未定义的行为。
  • 您确实意识到 malloc(x) 可以使用比 x 更多的字节 - 这些额外的字节用于管理。
  • @Someprogrammerdude,(定义明确的)指针减法的结果是ptrdiff_t,它不一定与size_t 类型相同。打印一个的最好方法可能是首先将其转换为您知道其格式说明符的整数类型。

标签: c


【解决方案1】:

您不能对指向单独数组的指针使用指针算法。 ab 是两个不同的数组。

C17 6.5.6 强调我的:

如果两个指针 操作数和结果指向同一数组对象的元素,或最后一个 数组对象的元素,评估不应产生溢出; 否则,行为未定义

因此b-a 没有明确定义的结果。它可以是任何东西。因此memset(... , b-a); 调用未定义的行为并且可能写入超出数组的范围。或者编译器可以将b-a 替换为零。

此外,不能保证ab 在内存中是相邻分配的。动态分配函数的堆管理器部分可以在任何地方添加大小字节和填充字节。堆可能会被分段并强制分配在完全不同的地方完成。或者b 可以分配在比a 更低的地址,因为不要求堆使用向上计数分配。 (例如,大多数堆栈都使用递减计数。)

所以是的,这非常容易受到攻击,因为整个程序充满了错误,并且随时可能崩溃。 “堆溢出”,如果存在这样的术语,宁愿指正在使用的堆的所有内存,而这不是这里发生的事情。

【讨论】:

    【解决方案2】:

    b-a 最小正值可能是 8 字节的标头,12 字节的数据,四舍五入到最接近的 8 倍数,所以 24。它也可能是负数,不能保证 b 更大地址比a。它也可以是其他任何东西,或者让你的程序做任何事情,因为不相关(不是同一个数组或分配的缓冲区)指针之间的指针算术是未定义的行为

    但我们假设它是有效值 24(Undefined Behavior 当然允许它是你所期望的,因为它允许任何事情)。您将 24 个字节的内存设置为大小为 12 的缓冲区。这是缓冲区溢出。

    【讨论】:

      猜你喜欢
      • 2010-11-11
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 2010-11-10
      • 2013-11-06
      相关资源
      最近更新 更多