본문 바로가기

CERT C/전처리기

[CERT C/전처리기] (1) 매크로 함수의 취약성

의미

매크로 함수란, #define 지시문에 인수로 함수의 정의를 전달하여서 함수처럼 동작하는 매크로이다.

 

동작 방식

매크로 함수는 인수를 컴파일 이전에 미리 치환하는 동작 방식이다.

 

문제 코드 1. 인자에 대한 연산이 발생시키는 오류

출력을 예상해보기

#include <stdio.h>
#define CALC(x) ((x) * (x))

int main()
{
    int a = 2;
    int b = CALC(++a);

    printf("%d\n", b);
    return 0;
}

 

정답은 "전처리기에 따라 달라진다" 입니다.

취약점 분석 및 해결 코드 1

분석 : 사용자가 a를 ++로 3인 상태를 넘겨서 3 * 3 = 9인 값을 원했다면 원하는 답이 나오지 않을 가능성이 높습니다.

3 * 4 = 12가 나올 수도 있고 4 * 4 = 16이 나오는 전처리기도 있을 것입니다. 그 이유는 [매크로 함수는 인수를 컴파일 이전에 미리 치환하는 동작 방식입니다.] 이 동작 방식 때문입니다.

 

해결 방법 : 매크로 함수보다는 인라인 함수, 정적 함수를 사용해라. 

종류 함수 수행 원리 특징
매크로 함수 컴파일 전에 전처리기에 의해 치환 (Text 형태로 치환) int, char, struct 등 타입에 제한이 없다
인라인 함수 ( inline ) Compiler에 의해서 치환되고 함수 호출부가 함수의 몸체부로 대체된다. 
(바이너리 형태로 치환)
inline 키워드로 선언된 함수라도 inline 함수로 만들어지는 컴파일러가 결정한다.
정적 함수 ( static ) 일반적인 함수로 수행된다. 함수가 정의된 파일 내에서만 호출이 가능하다.

 

#include <stdio.h>
#define CALC(x) ((x) * (x))

inline int CALC(int x){
	return x * x;
}

int main()
{
    int a = 2;
    int b = CALC(++a);

    printf("%d\n", b);
    return 0;
}

 

출력 : 9

 

문제 코드 2. 연산 순서 오류

출력을 예상해보기

#include <stdio.h>
#define CALC(x) (x) * (x)

int main()
{
    int a = 3;
    int b = 81 / CUBE(a);

    printf("%d\n", b);
    return 0;
}

 

출력 : 81 / 3 * 3 = 81

취약점 분석 및 해결 코드 2

분석 : CUBE가 인수의 제곱을 반환하는 함수라고 가정했을 때 위와 같이 입력하면 81 / (3 * 3) 이 아닌 81 / 3 * 3 으로 텍스트가 치환되어서 원하는 81 / 9 = 9 가 아닌 81이 나오게 된다

 

해결 방법 : 치환 목록을 소괄호() 로 묶어주고 우선순위를 확실히 한다.

#include <stdio.h>
#define CALC(x) ((x) * (x))

int main()
{
    int a = 3;
    int b = 81 / CUBE(a);

    printf("%d\n", b);
    return 0;
}

 

출력 : 9

 

POINT

  • 매크로 함수 호출 시 인자에 대한 변화가 있을 경우동작 방식에 의해원하는 결과를 얻기 어려우므로 inline, 정적 함수를 만들어서 사용한다.
  • 매크로 함수의 치환 목록은 괄호로 둘러싼다.

 

참조


PRE00-C. Prefer inline or static functions to function-like macros

wiki.sei.cmu.edu/confluence/display/c/PRE00-C.+Prefer+inline+or+static+functions+to+function-like+macros

PRE01-C. Use parentheses within macros around parameter names

wiki.sei.cmu.edu/confluence/display/c/PRE01-C.+Use+parentheses+within+macros+around+parameter+names