데비안 GNU / 리눅스 9 시스템에서 바이너리가 실행될 때
- 스택은 초기화되지 않았지만
- 힙은 0으로 초기화됩니다.
왜?
나는 0으로 초기화하면 보안을 촉진한다고 가정하지만 힙의 경우 스택도 아닌 이유는 무엇입니까? 스택에도 보안이 필요하지 않습니까?
내 질문은 내가 아는 한 데비안에만 국한된 것은 아닙니다.
샘플 C 코드 :
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
const size_t n = 8;
// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
const int *const p, const size_t size, const char *const name
)
{
printf("%s at %p: ", name, p);
for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
printf("\n");
}
// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()
{
int a[n];
int *const b = malloc(n*sizeof(int));
print_array(a, n, "a");
print_array(b, n, "b");
free(b);
return 0;
}
산출:
a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0
C 표준은 malloc()
물론 메모리를 할당하기 전에 메모리를 지우 도록 요구하지는 않지만 C 프로그램은 단지 설명을위한 것입니다. 이 질문은 C 나 C의 표준 라이브러리에 관한 질문이 아닙니다. 오히려, 질문은 왜 커널 및 / 또는 런타임 로더가 스택을 제외하고 힙을 제로화하는지에 대한 질문입니다.
다른 실험
내 질문은 표준 문서의 요구 사항이 아닌 관찰 가능한 GNU / Linux 동작에 관한 것입니다. 무슨 뜻인지 확실하지 않은 경우이 코드를 사용하면 추가 정의되지 않은 동작 ( 정의되지 않은, 즉 C 표준에 관한 한)을 호출 하여 요점을 설명 할 수 있습니다.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
const size_t n = 4;
int main()
{
for (size_t i = n; i; --i) {
int *const p = malloc(sizeof(int));
printf("%p %d ", p, *p);
++*p;
printf("%d\n", *p);
free(p);
}
return 0;
}
내 기계에서 출력 :
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
C 표준에 관한 한, 행동은 정의되어 있지 않으므로 제 질문은 C 표준을 고려하지 않습니다. 호출 할 malloc()
때마다 동일한 주소를 반환 할 필요는 없지만이 호출 malloc()
은 매번 같은 주소를 반환하기 때문에 힙에있는 메모리가 매번 0으로 표시됩니다.
대조적으로 스택은 0으로 보이지 않았습니다.
GNU / Linux 시스템의 어떤 계층이 관찰 된 동작을 일으키는 지 알 수 없기 때문에 후자의 코드가 시스템에서 무엇을할지 모르겠습니다. 시도해 볼 수 있습니다.
최신 정보
@Kusalananda는 의견에서 관찰했습니다.
가치가있는 것에 대해 가장 최근의 코드는 OpenBSD에서 실행될 때 다른 주소와 (때로는) 초기화되지 않은 (0이 아닌) 데이터를 반환합니다. 이것은 분명히 당신이 리눅스에서 목격하는 행동에 대해 아무 말도하지 않습니다.
내 결과가 OpenBSD의 결과와 다르다는 것은 실제로 흥미 롭습니다. 분명히, 내 실험은 내가 생각한 것처럼 커널 (또는 링커) 보안 프로토콜이 아니라 단순한 구현 아티팩트를 발견했습니다.
이 관점에서, @mosvy, @StephenKitt 및 @AndreasGrapentin의 아래 답변이 내 질문을 해결했다고 믿습니다.
스택 오버 플로우 : malloc이 gcc에서 0으로 값을 초기화하는 이유 도 참조하십시오 . (신용 : @bta).
new
C ++ 의 연산자 ( "힙")는 Linux에서 malloc ()의 래퍼 일뿐입니다. 커널은 "힙"이 무엇인지 모르거나 신경 쓰지 않습니다.