취약한 바이너리 인터페이스

Fragile binary interface problem

취약바이너리 인터페이스 문제(FBI)는 특정 객체 지향 프로그래밍 언어 컴파일러의 단점으로, 기본 클래스 라이브러리에 대한 내부 변경으로 인해 하위 라이브러리 또는 프로그램이 작동을 중지할 수 있습니다.이것은 소프트웨어의 취약성 예시입니다.

이 문제는 종종 취약한 기본 클래스 문제 또는 FBC라고 불리지만, 이 용어는 더 넓은 의미를 가지고 있습니다.

원인

이 문제는 많은 공통 객체 지향(OO) 언어용 컴파일러에서 사용되는 "바로 가기"로 인해 발생합니다. 이는 OO 언어가 C 및 Pascal과 같은 이전의 비OO 구조 프로그래밍 언어에서 진화할 때 유지되었던 설계 기능입니다.

이러한 언어에는 현대적 의미의 사물이 없었지만, 하나의 메모리에 다양한 관련 정보를 저장하는 레코드(또는 C의 "구조")로 알려진 유사한 구조가 있었다.특정 레코드 내의 부품은 레코드의 시작 위치를 추적하고 해당 시작 지점에서 해당 부품까지의 오프셋을 파악함으로써 액세스되었습니다.예를 들어, "개인" 레코드는 프로그래머가 쓰는 이니셜에 액세스하기 위해 이름, 성, 중간 이니셜을 가질 수 있습니다.thisPerson.middleInitial컴파일러는 이런 식으로 변합니다.a = location(thisPerson) + offset(middleInitial)최신 CPU에는 일반적으로 이 일반적인 종류의 액세스에 대한 지침이 포함되어 있습니다.

오브젝트 지향 언어 컴파일러가 처음 개발되었을 때 기존 컴파일러 기술의 대부분이 사용되었으며 오브젝트는 레코드 개념 위에 구축되었습니다.이러한 언어에서 개체는 시작점에 의해 참조되었고 "필드"로 알려진 공용 데이터는 알려진 오프셋을 통해 액세스되었습니다.사실상 유일한 변경은 레코드에 다른 필드를 추가하는 것입니다.이러한 필드는 각 클래스의 불변의 가상 메서드 테이블을 가리키도록 설정되어 레코드에 데이터와 메서드(함수)가 모두 기술됩니다.컴파일 시 오프셋은 (가상 메서드테이블을 통해) 데이터와 코드 모두에 액세스하기 위해 사용됩니다.

증상

이로 인해 라이브러리로 구성되는 대형 프로그램에서 문제가 발생합니다.라이브러리 작성자가 개체 내 공용 필드의 크기 또는 레이아웃을 변경하면 오프셋이 비활성화되고 프로그램이 더 이상 작동하지 않습니다.이건 FBI 문제입니다

구현의 변화가 문제를 일으킬 것으로 예상되지만 FBI의 음흉한 점은 컴파일된 라이브러리에 숨겨져 있는 오브젝트의 레이아웃만 다를 뿐 실제로 변경된 것은 없다는 것입니다.누군가 바뀌면 이렇게 생각할 수 있다.doSomething로.doSomethingElse문제를 일으킬 수 있지만 이 경우 변경하지 않고 문제를 일으킬 수 있습니다.doSomething알기 쉽게 하기 위해 소스코드의 줄을 움직이는 것처럼 쉽게 발생할 수 있습니다.게다가 프로그래머는 컴파일러에 의해 생성된 레이아웃에 대한 제어가 거의 없거나 전혀 없기 때문에 이 문제는 거의 보이지 않게 됩니다.

복잡한 객체 지향 프로그램이나 라이브러리에서 최상위 클래스는 수십 개의 클래스에서 상속될 수 있습니다.이러한 기본 클래스 각각은 수백 개의 다른 클래스에도 상속될 수 있습니다.이러한 기본 클래스는 이러한 기본 클래스 중 하나를 조금만 변경해도 직접 또는 다른 클래스에서 상속되는 모든 클래스에 문제가 발생할 수 있기 때문에 취약합니다.이로 인해 많은 클래스가 기본 클래스로 변경되어 손상되므로 라이브러리가 카드집처럼 붕괴될 수 있습니다.상속 트리가 복잡한 경우 수정 내용을 작성할 때 문제가 발견되지 않을 수 있습니다.실제로 기본 클래스를 수정하는 개발자는 일반적으로 다른 사람이 개발한 클래스가 어떤 클래스를 사용하고 있는지 알지 못합니다.

솔루션

언어들

취약한 바이너리 인터페이스 문제에 대한 해결책 중 하나는 문제가 존재함을 알고 처음부터 발생하지 않도록 하는 언어를 쓰는 것입니다.대부분의 사용자 지정 OO 언어는 이전 언어에서 발전한 것과 달리 로드 시 모든 오프셋 테이블을 구성합니다.라이브러리 레이아웃의 변경은 이 시점에서 "알립니다".Self와 같은 다른 OO 언어들은 라이브러리에서 발견된 오브젝트를 복사하고 수정함으로써 런타임에 모든 것을 구성하기 때문에 실제로 취약할 수 있는 기본 클래스가 없습니다.Java와 같은 일부 언어에는 FBI 문제를 일으키지 않고 어떤 변경을 안전하게 수행할 수 있는지에 대한 광범위한 문서가 있습니다.

또 다른 해결책은 메타 데이터라고 알려진 컴파일 단계에서 오프셋 및 기타 정보를 나열하는 중간 파일을 쓰는 것입니다.그런 다음 링커는 라이브러리에 로드될 때 이 정보를 사용하여 자체 수정 작업을 수행합니다.등의 플랫폼.NET은 이것을 실시합니다.

그러나 시장에서는 C++와 같은 "위치에 의존"하여 FBI를 나타내는 프로그래밍 언어를 선택하고 있습니다.이러한 경우, 이 문제에 대한 해결 방법이 아직 많이 있습니다.향후 추가 기능을 추가할 필요가 있는 경우에 대비하여 라이브러리 작성자에게 "플레이스 홀더" 개체를 여러 개 삽입하도록 하는 것이 라이브러리 작성자에게 부담이 됩니다(이것은 DirectX 라이브러리에서 사용되는 구조에서 확인할 수 있습니다).이 솔루션은 더미가 소진될 때까지 유효합니다.메모리를 소비하기 때문에 너무 많이 추가할 필요는 없습니다.

Objective-C 2.0은 인스턴스 변수접근에 대한 추가 수준의 간접성을 제공함으로써 비취약 인스턴스 변수를 제공합니다.

또 다른 부분적인 해결책은 "Pimpl"("실장 포인터")로 알려진 브리지 패턴을 사용하는 것입니다.Qt 프레임워크는 이러한 구현의 한 예입니다.각 클래스는 구현 데이터를 보유하는 구조에 대한 포인터인 데이터 멤버를 하나만 정의합니다.포인터 자체는 (특정 플랫폼에 대해) 변경되지 않으므로 구현 데이터를 변경해도 공용 구조의 크기에 영향을 주지 않습니다.그러나 이렇게 해도 가상 메서드가 없는 클래스에 도입되거나 상속 그래프를 변경하는 등의 다른 변경 중단은 피할 수 없습니다.

링커

또 다른 솔루션에는 보다 스마트한 링커가 필요합니다.Objective-C의 원래 버전에서는 라이브러리 형식이 하나의 라이브러리의 여러 버전을 허용하고 호출 시 적절한 라이브러리를 선택하는 기능을 포함했습니다.그러나 메서드 오프셋이 런타임에 수집되어 FBI의 원인이 되지 않았기 때문에 오프셋이 필드에만 필요했기 때문에 이것이 항상 필요한 것은 아니었습니다.ObjC는 필드보다 메서드가 더 자주 변경되기 때문에 애초에 FBI의 문제가 거의 없었으며 버전 관리 시스템으로 수정할 수 있었습니다.Objective-C 2.0에는 "현대 런타임"이 추가되어 필드에서도 FBI 문제가 해결되었습니다.또한 TOM 언어는 모든 것에 대해 런타임 수집 오프셋을 사용하기 때문에 FBI가 불가능합니다.

응용 프로그램을 다시 컴파일하고 사용하는 오프셋을 업데이트하지 않으면 라이브러리를 수정할 수 없기 때문에 가능한 경우 동적 라이브러리 대신 정적 라이브러리를 사용하는 것도 다른 해결책입니다.그러나 정적 라이브러리에는 더 큰 바이너리와 새로운 버전의 라이브러리를 도입할 때 "자동"으로 사용할 수 없는 등의 심각한 문제가 있습니다.

아키텍처

이러한 언어에서는 단일 상속을 실시함으로써 문제가 경감됩니다(이것에 의해 상속 트리의 복잡성이 경감됩니다).또, 인터페이스 자체에 코드가 포함되어 있지 않기 때문에, 가상 기능이 있는 베이스 클래스가 아닌 인터페이스를 사용함으로써, 인터페이스가 선언하는 각 메서드시그니처만이, Everyone에 의해서 서포트되고 있는 것을 보증합니다.인터페이스를 실장하는 오브젝트.

배포 방법

라이브러리의 소스 코드를 사용할 수 있으면 문제 전체가 축소됩니다.그럼 간단한 재컴파일만 하면 되겠네요.

「 」를 참조해 주세요.

외부 링크