2017. 7. 30. 08:51ㆍSecurity ★ Development/시큐어코딩
malloc을 사용한 경우 free를 사용해 메모리를 해제하게 됩니다. 보통은 이것으로 충분하지만 좀 더 안전한 코딩을 위해서는 습관을 들이면 좋은 코딩이 있습니다. 개발을 할 때 디버깅을 하는 측면에서도 좋고 집요한 메모리 해킹에 대한 대비책이 될 수도 있습니다.
malloc - free
우선 malloc과 free만 사용한 경우입니다.
calloc을 썼지만 크게 차이는 없고 윈도우환경에 비쥬얼 스튜디오 디폴트 설정, c파일입니다. free를 한 후에도 주소값은 그대로 확인이 가능하고 1 1 1 을 넣어뒀던 데이터는 읽을 수 없게 되었습니다. 이 글의 효율을 높이기 위해선 값도 그대로 읽을 수 있길 바랬는데 못 읽는군요.
+
리눅스에서 address sanitizer, kasan 등의 메모리 관리 옵션을 끄고 접근을 하면 free를 하더라도 주소를 통해 데이터를 읽을 수 있습니다. 옵션을 끄지 않으면 malloc 등이 구현된 libc에서 왜 free한 주소에 접근을 하냐며 에러를 발생시킬 수 있습니다. 실제 data가 저장된 paga를 구해놓고 free한 후에 다시 접근해서 보는 경우에도 데이터가 그대로 남아있다는것을 확인 할 수 있습니다.
이런 메모리 zeroing 관련 동작은 kconfig, libc config에 따라 조정될 수 있지만 대부분 off 상태로 데이터 확인이 가능합니다.
malloc - memset, free
덕분에 calloc 후 free하기전 할당받은 버퍼를 0으로 memset한 결과도 같습니다. 하지만 free를 하였기 때문에 데이터를 읽을 수 없을 뿐이고 메모리 상으로는 값이 남아있는지의 여부가 분명치 않습니다. 고레벨 언어에서는 내부 함수가 위와 같은 결과를 가져오도록 편하게 되어있지만 그렇지 않은 경우도 있기때문에 코드 리뷰시 지적받는 부분이기도 합니다. (현재 환경의 경우 해당 메모리 영역을 약간 아래부터 쭉 스캔하다보면 역시 ????의 값으로 나옵니다.)
malloc - null, free
다음은 calloc 후 free하기전, 해당 버퍼에 null을 할당하였습니다. memeset zero는 하지 않았습니다.
mem3 및 memp3의 주소는 모두 0이 나오네요. null로 할당했으니까요. 해당 변수의 값을 읽으려고 하다보니 런타임 에러가 발생합니다. 잘못된 주소를 참조한다고 합니다. 이 경우 역시 데이터는 원래의 008CB058에 남아있을 수 있습니다. free가 메모리영역의 zero화를 하지 않았다면요.
하지만 이렇게 null로 할당한 경우는 디버깅 시에도 효과를 보는데 memset도 마찬가지고 애매한 주소와 애매한 값들이 잘못 들어있는 것보다 확실히 null값을 가지는 변수를 사용하려고 하는경우 수월한 디버깅이 될 수 있습니다. null값의 참조는 런타임 에러를 발생시키기도 하고요.
malloc - memset, null, free
제 환경에서 결과는 위와 같습니다만 기대할 수 있는 건 memset zero를 해줌으로써 메모리상에 남아있을 수 있는 데이터를 지워줍니다. 변수에 할당된 주소값도 초기화를 해주고요.
전체 코드는 아래와 같은 모습이 될 겁니다.
unsigned char *mem4=NULL;
mem4 = (unsigned char *)calloc(fullsize, sizeof(unsigned char));
...
if(mem4!=NULL){
memset(mem4, '0', fullsize);
free(mem4);
mem4 = NULL;
}
C#, 자바는 GC를 기본적으로 두고 있지만 개발시 이런 면을 항상 염두에 두면 자신이 할당한 것들이 어디까지 쓰일 수 있는지 확실히 인지가 되고 memory leak을 방지하는 등 좀 더 최적화된 개발이 될 것입니다.