5.3. C/C++ 에서의 컴파일 솔루션

완전히 다른 접근 방법은 경계 검사를 하는 컴파일 방법을 사용하는 것이다 ([Sitaker 1999] 를 참조해라). 저자 의견으로는 이러한 도구는 다수의 보호 계층를 갖는 경우 매우 유용하지만 유일한 보호책으로 이 기법을 사용하는 것은 현명하지 않다. 이에 대해서는 적어도 두가지 이유가 있다. 우선 대부분의 이러한 도구들은 버퍼 오버플로우에 대한 부분적인 보호만을 제공한다 (완전한 보호는 일반적으로 12-30 배 정도 느리다); C 와 C++ 은 단순히 버퍼 오버플로우에 대해 보호하도록 설계되지 않았다. 두번째 오픈 소스 프로그램에 대해 프로그램을 컴파일하기 위해 어떤 도구가 사용될 것이라는 것을 확신할 수 없다; 주어진 시스템에 대해서 ``통상적인" 컴파일러를 사용하는 것이 갑자기 보안 결함을 제공할 수도 있다.

가장 유용한 도구중의 하나는 표준 GNU C 컴파일러 gcc 를 수정한 "StackGuard" 이다. StackGuard 는 ``canary" 라고 불리는 ``guard" 값을 반환 주소 앞에 추가함으로써 작동한다; 버퍼 오퍼플로우가 반환 주소를 겹쳐쓰면 canary 값이 변경되어 시스템은 이를 사용하기 전에 이를 탐지한다. 이는 매우 유익하지만 다른 값을 겹쳐쓰는 버퍼 오버플로우 공격을 예방하지는 못한다. canary 를 ``PointGuard" 라고 불리는 다른 데이타 아이템에 추가할 수 있도록 StackGuard 를 확장한 작업이 있다. PointGuard 는 자동적으로 특정 값을 보호할 것이다 (예, 함수 포인터 및 longjump 버퍼). 그러나 PointGuard 를 사용해서 다른 변수 타입을 보호하기 위해서는 특정 프로그래머의 중재를 필요로 한다 (프로그래머는 canary 를 이용해 어떤 데이타 값이 보호되어야 하는 지를 식별해야 한다). 이는 유익할 수 있지만 보호가 필요하다고 (그러나 어쨋든 보호가 필요한) 생각하지 못했던 데이타 값에 대한 보호를 우연히 생략하기가 쉽다 . StackGuard, PointGuard 및 다른 대안에 대해 더욱 자세한 정보는 Cowan [1999] 를 참조해라.

관련 문제로써 리눅스에서는 커널을 수정해서 스택 세그먼트를 실행불가능하게 만들 수 있다; 이러한 패치가 존재한다 (Solar Designer 의 패치를 보라 http://www.openwall.com/linux/ ). 그러나 이 문서 작성 시점에서 이는 리눅스 커널내로 구축되지 않았다. 이 근본적 이유의 일부분은 이것이 생각하는 것만큼 보호를 하지 않는다는 것이다; 공격자가 간단히 시스템으로 하여금 프로그램내 다른 ``interesting" 위치를 호출하도록 할 수 있다 (예, 라이브러리, 힙 또는 정적 데이타 세그먼트내). 또한 때때로 리눅스에서는 예를 들어 시그널 및 GCC ``trampolines" 를 구현하기 위한 경우와 같이 스택에 실행가능한 코드가 있어야 한다. Solar Designer 패치는 이런 경우를 다루지만 패치를 복잡하게 만든다. 개인적으로 저자는 이것이 어느정도 공격을 어렵게 만들고 기존의 다양한 공격들에 대해 보호하기 때문에 주요 리눅스 배포판에 결합되는 것을 보고 싶다. 그러나 저자는 이것이 생각하는 것만큼 많은 보호를 추가하지 못하며 비교적 쉽게 뚫어질 수 있다는 리누스 토발즈와 다른 이에 동의한다. http://lwn.net/980806/a/linus-noexec.html 에서 이 지원을 포함하지 않는 리누스 토발즈의 설명을 읽을 수 있다.

요약하면 자체적으로 버퍼 오버플로우를 보호하는 정확한 프로그램을 개발하는 데 우선적으로 중점을 두는 것이 더욱 좋다. 따라서 여러분이 이를 다 읽은 후 반드시 추가적인 안전망으로써 StackGuard 와 같은 기법 및 도구를 사용해라. 코드 자체에서 버퍼 오버플로우를 제거하기 위해 더욱 더 작업한다면 보호를 위해 StackGuard 가 호출될 "약점"은 없을 것이기때문에 StackGuard 는 더욱 더 효과적일 것같다.