UEFI 스터디 13차 - OobHunter 로직 개선하기(2)
Published:
최적화의 범인을 찾아라
이전 모임의 테스트 관련 이슈
- 나의 코드 -> TEMP = X * Y => result = TEMP * 4 만잡아야한다.
- 용진이형의 테스트에서 뜬금 없이 TEMP = X * Y => result = TEMP + TEMP + TEMP + TEMP도 캐치.
=> 범인은 빌드도구와 기드라 중 누구이며 어떻게 개선해야할까?
어셈블리로 접근
기드라 좌측에 리스팅에선 low pcode보다 앞서 어셈블리를 보여줌.
- 기드라의 탓 -> 다른 어셈블리 코드를 가지고 있으나 우측 디컴파일된 C언어나 p코드쪽에서 변화가 있다
- 빌드도구 탓 -> 어셈블리 기계어는 1대1인데 다른 C코드로 작성된 드라이버가 동일한 어셈블리 코드 가짐
테스트할 리스트들
(test_0, 곱하기)

(test_0_1, 쉬프트)

(test_0_2, 덧셈 네번)

결과

모두 SHL 어셈블리로 번역 => 범인은 빌드 도구
그러나

시프트 어셈블리 연산 => INT_MULT 하이피코드 op로 번역이 되었다.
=> 빌드전 C코드가 다름 != 테스트 드라이버가 다름 + 연산도 비슷한걸로 바뀔거라 확신 못함
개선해야 할 점
- high p-code에서의 분석인 만큼, 명세도 high pcode적 맥락이 들어가야할 것 같음. 단순 곱셈했다, 덧셈했다로는 너무 모호함.
- 검증 쪽에서는 다른 c코드 + 같은 하이 피코드를 어떻게 할지 고민해봐야..
스크립트 개선하기 - 비교 여부 검증 파트
기존의 코드
- 위험한 연산에 쓰이는 변수가 특정 상수에 작다크다 비교하기만 해도 => 안전.
- ‘비교하는 상수가 매우 크다면?’이라는 것에 취약
접근 방식
비교의 가능한 케이스가 너무너무너무너무 많음. => 이전 문제가 있던 드라이버가 어떻게 문제를 개선했는지 찾아보자.
이전에 한 방식 그대로 이번엔 최신 펌웨어에서 문제가 개선된 드라이버를 획득했다.

상용드라이버라고 뭔가 화려한게 있을거라 기대했으나 외부 인풋이 0인지 대한 검사가 끝이다.
정수 오버플로우가 문제가 아니라고?
- 로고페일 CVE가 정수 오버플로우와 관련이 깊긴하지만
- 이 보고서에는 정수 오버플로우는 딱히 문제 삼지 않았다.
아마 이 드라이버 프로토콜을 쓰는 다른 드라이버에서 오버플로우 관련은 검사를 하거나
(이전 게시글에서 언급했듯, 해당 외부 인풋은 getvariable로 들고온게 아닌, 타 드라이버에서 가져와 넘겨준거다.)
매우매우 낮은 확률이지만 진짜 오버플로우 케이스를 빼먹었거나 일 것 같다.
암튼. 곱셈이란 연산 특성상 0이 곱해지는 것도 매우 위험. 0 크기 버퍼가 할당 될테니.
해당 검증 로직이 조잡해보여 edk2의 이미지 관련 파싱 라이브러리를 찾아서 이를 검증하는 법을 확인했다.
(신기하게도 라이브러리도 GUID는 있다. 그대로 드라이버 코드에 포함되니 ovmf 파일에는 검색해도 안나온다.)
edk2의 이미지 파싱 검증 로직
Bmp로고이미지를 메모리 버퍼에 로딩하는 라이브러리

오..
있다. 여기도 있다. 나름 0크기 버퍼 할당 방지를 위한 유구한 문화인것 같다.
그리고 다행히도 여긴 오버플로 대책이 있는데 이게 꽤나 특이하다.


별도의 곱셈함수가 있다.
위험한 곱셈에 대한 대응책으로 그냥 곱셈이 아닌 함수를 선택한 듯하다.
이외에도 있는 것까지 포함해서 모든 edk2의 해당 이미지 파서의 OOB 방지 정책을 보면
- 위험한 연산에 사용될 외부 유입 변수가 0인지 체크 => 크기 0 방지
- 오버플로우를 막기위해 별도의 비교 없이 오버플로 탐지하는 곱셈 함수를 사용
- 실제 헤더의 값이 변조되었는지 확인(이건 무리로 판단. 어떤 변수, 구조체가 헤더인지 알수가 없다. + 메모리에 접근)
그러니 우리는 일단 오버플로는 잊고, 첫 조건 (변수 != 0) 먼저 잡아보자.
참고해 만든 비교부분 소스코드.

high pcode 모습도 매우 단순하다.
로직
- 변수가 int_equal pcodeop에 사용되는가?
- 비교 대상이 0x0 인가가
변수 0 검사로 가니 오히려 검증코드가 단순해짐. (물론 오버플로우 관련도 추가할것.)
추가로 기존 조건문 검증의 코드에 심각한 오류가 있었다. (3단계 도달하면 무조건 검출 수준의 오류) 이것도 수정완료했다.
(간단한 요약 temp = x*y 를 검증해야하는데 temp1 = temp*4를 검증했다.)

안전한건 잘 거르고

위험한건 잘 잡는다.
남은 보충 할 것
- 검증용 if 문이 비어있거나 별 의미 없다면?
- 오버플로우 탐지로직.
