※ Memory 참조 버그 예제

typedef struct {
    int a[2];
    double d;
} struct_t;

double func(int i) {
    volatile struct_t s;
    s.d = 3.14;
    s.a[i] = 107374824;
    return s.d;
}

 

 

cf. volatile 변수 소개

C/C++ 프로그래밍 언어에서 최적화 등 컴파일러의 재량을 제한하는 역할을 한다.
개발자가 설정한 개념을 구현하기 위해 코딩된 프로그램을 온전히 컴파일되도록 한다.
주로 최적화와 관련하여 volatile가 선언된 변수는 최적화에서 제외된다.
OS와 연관되어 장치제어를 위한 주소체계에서 지정한 주소를 직접 접근하는 방식을 지정할 수도 있다.
Linux Kernel 등의 OS에서 메모리 주소는 논리주소와 물리주소 간의 변환이 이루어진다.
경우에 따라 이런 변환을 제거하는 역할을 한다. 또한 원거리 메모리 점프 기계어 코드 등의 제한을 푼다.
C언어의 경우, 주로 메모리 맵 입출력(MMIO)을 제어할 때,
volatile을 선언한 변수를 사용하여 컴파일러의 최적화를 못하게 하는 역할을 한다.
static int foo;

void bar(void) {
    foo = 0;
    while (foo != 255);
}
foo의 값의 초기값이 0 이후, while 루프 안에서 foo의 값이 변하지 않기 때문에 while의 조건은 항상 true가 나온다. 따라서 컴파일러는 다음과 같이 최적화한다.
void bar_optimized(void){
    foo = 0;
    while (true);
}

이렇게 되면 while의 무한 루프에 빠지게 된다. 이런 최적화를 방지하기 위해 다음과 같이 volatile을 사용한다.

static volatile int foo;

void bar (void) {
    foo = 0;
    while (foo != 255);
}
이렇게 되면 개발자가 의도한 대로, 그리고 눈에 보이는 대로 기계어 코드가 생성된다.
이 프로그램만으로는 무한루프라고 생각할 수 있지만, 만약 foo가 하드웨어 장치의 레지스터라면 하드웨어에 의해 값이 변할 수 있다.
따라서 하드웨어 값을 폴링(polling)할 때 사용할 수 있다.

 

※ Memory 참조 버그 (= Buffer Overflow)의 심각성

배열에 할당된 크기 이상의 메모리를 접근할 때 주로 발생한다.

가장 빈번하게 발생하는 보안 취약성의 원인이 된다.

§ 가장 일반적인 형태로는 다음과 같다.
- string 입력의 길이를 check하지 않은 경우 
- stack에 생성되는 제한된 길이의 문자배열

 

§ UNIX의 gets 함수 (키보드를 관리해주는 라이브러리)

/* Get string from stdin */

char *gets (char *dest) {
	int c = getc();
    char *p = dest;
    while (c != EOF && c != '\n') {
    	*p++ = c;
        c = getc();
	}
    *p = '\0';
    return dest;
}
cf. 유사한 문제
- strcpy: 임의의 길이의 string을 복사
- scanf, fscanf, sscanf 함수를 %s와 함께 사용하는 경우

 

 

§ 위험한 buffer 코드

/* Echo Line */
void echo() {
	char buf[4];
    gets(buf);
    puts(buf);
}


int call_echo () {
	printf("Type a string: ");
    echo();
    return 0;
}

 

§ stack 상태

 

 

 

 

§ Buffer Overflow를 피하는 방법

※ string의 길이를 제한하는 라이브러리를 사용하면 된다! ( buffer 주소를 주면서 buffer크기를 check)

gets대신 fgets를 사용  
strcpy대신 strncpy를 사용
scanf를 %s와 함께 사용하지 않는다.  ( fgets를 사용한다. )
/* Echo Line */

void echo() {
	char buf[4];
    fgets(buf, 4, stdin);
    puts(buf);
}

+ Recent posts