58개 중 9개. 타입변환 오류, 자원(메모리 등)의 부적절한 반환 등과 같이 개발자가 범할 수 있는 코딩오류로 유발되는 보안약점.
관통 질문: 이 포인터와 이 자원의 “수명”은 어디까지인가? 4개 소분류(포인터/자원/정수/코드정확성)로 나눠 보되, 가이드 원문 번호(교육 순번 = 원문 번호) 순서로 적는다.
포인터 계열
1. 널(Null)포인터 역참조 CWE-476
신뢰 경계: getenv()/malloc() 등 실패 시 NULL 반환 → 검사 없이 → 포인터 역참조
⚠️ “반환값이 NULL일 수 있는 함수 목록”을 팀 표준으로 정하고, 역참조 직전에 무조건 검사하도록 습관화하라.
공격 시나리오: 서비스 거부(DoS)로 직결되며, 공격자가 의도적으로 역참조를 유발해 발생하는 예외 상황을 추후 공격 계획에 이용할 수 있다.
❌ Bad
p = getenv("CGI_HOME"); /* 미설정 시 NULL 반환 */strncpy(cgi_home, p, BUFSIZE-1); /* NULL 역참조 */
✅ Good
p = getenv("CGI_HOME");if (p == NULL) { exit(1); } /* 사용 전 NULL 검사 */strncpy(cgi_home, p, BUFSIZE-1);
치환 규칙: 변경될 수 있는 모든 포인터·함수 입력 인자·구조체 멤버 포인터는 사용 전 NULL 검사.
5. 스택 변수 주소 리턴 CWE-562
신뢰 경계: 함수 종료 → 지역 변수 소멸 → 반환된 포인터가 여전히 유효하다는 착각
⚠️ 반환하는 포인터가 가리키는 메모리의 “수명”을 항상 함수 계약(주석)으로 명시하라.
공격 시나리오: 해제된 스택 영역 접근은 예측 불가능한 값 변조·크래시를 유발하고, 증상이 즉시 나타나지 않아 디버깅이 매우 어렵다.
❌ Bad
char *rpl() { char p[10]; /* 스택 지역 배열 */ return p; /* 함수 종료 시 소멸되는 주소 */}
✅ Good
char *rpl() { char p[10]; char *buf = (char *)malloc(10); /* 힙에 할당 */ if (!buf) exit(1); memcpy(buf, p, 10); return buf; /* 함수 종료 후에도 유효, 호출자가 free */}
치환 규칙: 지역변수 주소 반환 금지 → malloc() 힙 할당 후 반환(호출자 free 책임) 또는 호출자 제공 버퍼에 채워 넣는 방식.
보충 — 구조체는 "값으로 반환"도 유효한 선택지다
위 Bad 예시는 배열(char p[10])의 주소를 반환하는 패턴이다. 배열은 포인터로 decay하므로 반환하는 순간 이미 죽은 스택 주소를 넘기는 셈이라 이 방식 자체가 성립하지 않는다. 하지만 구조체(struct)는 다르다 — C는 구조체를 “값”으로 반환하는 것을 언어 차원에서 지원한다. return p; 에서 p 가 구조체 지역변수면, 컴파일러가 p 의 내용을 통째로 복사해서 호출자에게 넘긴다. 넘어가는 건 p 의 주소가 아니라 p 의 복사본이므로 함수가 끝나 p 가 소멸해도 문제가 없다.
typedef struct { int x, y; char tag[16]; } Point;Point make_point(int x, int y) { Point p = { x, y, "origin" }; /* 지역 변수 */ return p; /* 구조체는 값으로 복사되어 반환된다 — p의 주소가 아니다 */}Point pt = make_point(1, 2); /* 호출자 스택에 통째로 복사됨. free 불필요, 소유권 문제 없음 */
작은 구조체(레지스터 몇 개, 십수 바이트 이내) 는 값 복사 반환이 낫다 — malloc/free 짝을 맞출 필요가 없고, 실패 시 NULL 체크·소유권 이전 같은 부가 로직이 통째로 사라진다.
구조체가 커질수록(배열 멤버가 크거나 중첩이 깊을 때) 값 복사 비용(스택 복사·caller 프레임 크기)이 커지므로, 이 노트의 Good 예시처럼 힙에 할당해 포인터로 반환하는 편이 맞다.
기준은 “포인터 하나보다 확실히 싼가”다 — 애매하면 일단 값 복사로 시작하고, 프로파일링에서 복사 비용이 드러날 때 힙+포인터로 바꿔도 늦지 않다.
자원 계열
2. 부적절한 자원 해제 CWE-404
신뢰 경계: 정상 종료 경로 → 에러/예외 경로에서는 검증 없이 → 자원(핸들·소켓) 미반환
⚠️ 자원 해제는 “정상 경로”가 아니라 “에러 경로”에서 빠진다. goto cleanup 같은 단일 해제 지점을 설계하라.
공격 시나리오: 누적된 미반환 자원이 메모리·핸들 고갈을 일으켜 시스템 전체가 서비스 불능(DoS) 상태에 빠진다.
❌ Bad
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env_hd);SQLAllocHandle(SQL_HANDLE_DBC, env_hd, &con_hd);/* 핸들을 반환하지 않고 함수 종료 -> 자원 누수 */