트램펄린 (컴퓨팅)
컴퓨터 프로그래밍에서 트램펄린(trampoline)은 프로그램 제어 흐름 점프(Jump)와 관련된 다양한 개념을 지칭할 때 사용되는 용어이다.
저수준 프로그래밍
[편집]저수준 프로그래밍에서 트램펄린은 인터럽트 서비스 루틴이나 입출력 루틴의 주소를 가지고 있는 메모리 공간을 가리키는 말으로, 종종 간접 점프 벡터(Indirect jump vector)라는 용어와 혼용되기도 한다. 트램펄린이라는 용어는 프로그램 컨트롤이 트램펄린으로 점프한 직후에 곧바로 다른 루틴의 주소로 다시 튕겨나가는 과정과 연관성이 있다.
트램펄린은 다음과 같은 다양한 용례가 존재한다:
- 중앙 처리 장치(CPU)의 인터럽트 벡터는 아키텍처적인 제약 사항으로 인해 반드시 미리 정해진 메모리 주소에 위치하여야 하는데, 해당 주소에 트램펄린을 설치하여 실제 기능을 구현하는 인터럽트 핸들러가 간접적으로 호출되게 하면 이러한 제약 사항을 극복할 수 있다.
- 대칭형 다중 처리(Symmetric Multiprocessing, SMP) 컴퓨터에서 부트스트랩 프로세서를 제외한 나머지 프로세서들은 부팅 후 환경 설정이 마무리 된 후에 활성화가 되는데, 이들 프로세서는 운영 체제에 의해 부팅 후에 제어 흐름이 트램펄린으로 점프되고, 이 트램펄린에서 대기하며 스케줄링되는 쓰레드를 기다린다.
고수준 프로그래밍
[편집]C
[편집]GCC 컴파일러에서 트램펄린은 지역 함수의 함수 포인터를 구현하기 위해 스택에 삽입되는 작은 코드 조각을 가리키는 말이다.[1]
지역 함수가 부모 함수의 지역 변수에 접근하기 위해선 부모 함수의 스택 프레임 주소, 즉 정적 링크 포인터(Static link pointer)가 필요한데, 지역 함수가 본인의 이름을 통해 직접 호출될 때에는 그 당시의 스택에서 정적 링크 포인터를 유추할 수 있지만, 함수 포인터를 통해 간접적으로 호출될 때에는 이 포인터에 대한 정보를 유추할 수 없다는 문제가 발생한다. 이 문제에 대한 해결책 중 하나로 함수 포인터를 뚱뚱하게 만들어 지역 함수의 포인터에 부모 함수의 스택 프레임 주소를 첨부시키는 방법이 있지만 (Fat function pointer),[2][3][4] 이 방식은 지역 함수의 함수 포인터를 일반적인 함수 포인터와 같은 방식으로 다룰 수 없게 만든다는 단점이 있다.[5]
대신 트램펄린을 사용하면 이 단점을 없애면서 정적 링크 포인터 문제를 해결할 수 있는데, 트램펄린을 함수 포인터를 통해 지역 함수를 호출할 때 사용하는 일종의 대리자로서 이용하는 방법이다. 구체적으로 트램펄린은 호출 직후에 정적 링크 포인터를 준비한 후에 바로 원래의 지역 함수로 제어 흐름을 전달해주는 역할을 하는데, 지역 함수의 주소가 취해질 때에 이 트램펄린의 주소를 대신 제공하면 모든 "함수 포인터를 통한" 지역 함수 호출이 이 트램펄린을 거쳐 이뤄지도록 할 수 있다.
이 때 트램펄린이 제공하는 정적 링크 포인터는 트램펄린의 코드 자체에 새겨져야 하는데, 함수의 스택 프레임 주소는 런타임에 동적으로 결정되므로, 트램펄린 코드 역시 런타임에 스택 상에 즉석으로 삽입되어야 한다. 하지만 이 점으로 인해 스택 전체를 실행 가능한 영역으로 만들어야 하는데, 이는 컴퓨터 보안상 스택을 실행 불가능하게 만드는 원칙과 상충된다.
실행 불가능한 스택
[편집]몇몇 트램펄린의 구현들은 실행 불가능한 스택(NX 스택)을 배제시키는 결과를 초래한다. 특히 GCC 컴파일러의 경우에는 지역 함수의 함수 포인터를 구현하기 위해 프로그램 실행 중에 스택에 트램펄린 코드가 주입되도록 하고, 지역 함수가 포인터로 호출이 되는 경우에 이 트램펄린을 경유하여 실행되도록 하는데, 트램펄린이 실행되기 위해선 스택 메모리의 실행 권한이 필요하다. 따라서 실행 불가능한 스택과 지역 함수 기능은 GCC에서는 상호 양립할 수 없는데, 이 점으로 인해 취약점 없는 소프트웨어를 개발하기 위해서는 지역 함수 사용을 지양하도록 권장되고 있다.[6]
GCC는 -Wtrampoline
옵션을 통해 트램펄린으로 인해 스택이 실행 가능해지는 경우에 컴파일러 경고를 출력하도록 하고 있다.
참조
[편집]- DLL trampolining
- 리트폴린
각주
[편집]- ↑ fuz (2011-11-18). "Implementation of nested functions". StackOverflow. Archived from the original on 2016-03-29. Retrieved 2018-05-26.
- ↑ "Trampolines for Nested Functions". Using the GNU Compiler Collection (GCC). 2018 [2002]. 18.11. Archived from the original on 2018-05-27. Retrieved 2018-05-26.
- ↑ "Nested functions". Using the GNU Compiler Collection (GCC). 2018 [2002]. 6.4. Archived from the original on 2018-05-27. Retrieved 2018-05-26.
- ↑ Breuel, Thomas M. (2013). "Lexical Closures for C++" (PDF). Archived (PDF) from the original on 2017-12-12. Retrieved 2018-05-26.
- ↑ C 언어의 함수 포인터는 함수의 주소 이외에는 어떤 추가 정보도 담고 있지 않다.
- ↑ Walton, Jeffrey; Manico, Jim; Wall, Kevin (2018년 3월 2일) [2013]. “C-Based Toolchain Hardening”. The Open Web Application Security Project (OWASP). 2018년 5월 27일에 원본 문서에서 보존된 문서. 2018년 3월 2일에 확인함.