3.7. 동적 링크 라이브러리

실제적으로 모든 프로그램은 실행되는 라이브러리에 의존하는데 리눅스를 포함한 현재 대부분의 유닉스 계열 시스템에서 프로그램은 동적 링크 라이브러리 (Dynamically linked libraries, DLLs) 를 사용하도록 컴파일된다. 이러한 방식에 의해 라이브러리를 갱신할 수 있으며 그 라이브러리를 사용하는 프로그램은 가능한 경우 새로운 버전 (아마도 향상된) 을 사용할 것이다.

동적 링크 라이브러리는 일반적으로 몇개의 특정 디렉토리들에 놓이는데 보통 /lib, /usr/lib, PAM 의 경우 /lib/security, X 윈도우의 경우 /usr/X11R6/lib/usr/local/lib 디렉토리들이 있다. 프로그램에서 이러한 표준 관례를 사용해야 하는데, 디버깅중이 아니라면 현재 디렉토리로부터 계산된 값을 동적 링크 라이브러리에 대한 소스로 사용하지 않아야 한다 (공격자가 자신이 선택한 ``라이브러리" 값을 추가할 수도 있을 것이다).

라이브러리 네이밍과 이들에 대한 심볼릭 생성에 있어 특별한 관례가 있다. 특히 심볼릭 생성을 통해 라이브러리를 갱신할 수 있으며 오래되고 역 호환성이 없는 라이브러리 사용을 원하는 프로그램을 지원할 수도 있다. 특별한 프로그램을 실행시킬 때 특정 라이브러리 또는 라이브러리내의 특정 함수만을 재정의할 수 있는 방법들도 있다. 이는 윈도우 계열 시스템에 대한 유닉스 계열 시스템의 장점이다; 저자는 유닉스 계열 시스템이 라이브러리 갱신에 대해 더욱 훌륭한 시스템이라고 믿고 있는데 이것이 유닉스와 리눅스 시스템이 윈도우 기반 시스템보다 더욱 안정하다고 평가되는 한가지 이유이다.

모든 리눅스 시스템을 포함하여 GNU glibc 에 기초한 시스템에서 프로그램 시동중에 자동적으로 검색되는 디렉토리 목록은 /etc/ld.so.conf 파일에 저장되어 있다. 많은 레드햇에서 파생된 배포판들은 일반적으로 /etc/ld.so.conf 파일에 /usr/local/lib 이 포함되어 있지 않다. 저자는 이를 버그라고 생각하는데 이러한 배포판에서 많은 프로그램들을 작동시키기 위해서는 /usr/local/lib 를 /etc/ld.so.conf 에 추가하는 수정 작업이 필요하다. 라이브러리에서 단지 몇개의 함수를 재정의하고 나머지를 그대로 이용하려면 /etc/ld.so.preload 에 재정의 라이브러리 (.o 파일) 이름을 넣어줄 수 있다; 이런 ``선적재" 라이브러리는 표준 라이브러리에 우선된다. 이 선적재 파일은 일반적으로 응급 패치를 위해 사용되는데 배포판은 출시될 때 일반적으로 이러한 파일을 포함하지 않을 것이다. 프로그램 시동시에 이런 모든 디렉토리를 검색하는 것은 매우 많은 시간이 걸리는데 실제로는 캐싱 방법이 사용된다. ldconfig(8) 프로그램은 디폴트로 /etc/ld.so.conf 파일을 읽어들여 동적 링크 디렉토리 (표준 관례를 따른다) 에 적절한 심볼릭 링크를 설정한 후 나중에 다른 프로그램이 사용할 캐시를 /etc/ld.so.cache 에 작성한다. 따라서 ldconfig 가 DLL 이 추가될때마다, DLL 이 제거될때 또는 DLL 디렉토리들이 변경될 때 실행되어야 한다; ldconfig 를 실행시키는 것은 라이브러리를 설치할 때 패키지 관리자가 자주 수행하는 조치중의 하나이다. 시동시 프로그램은 동적 로더를 사용해 /etc/ld.so.cache 파일을 읽어 들인 후 필요로 하는 라이브러리를 적재하는 것이다.

다양한 환경 변수가 이 프로세스를 제어할 수 있으며 사실 이 프로세스를 재정의할 수 있는 환경 변수가 있다 (따라서 특별한 프로그램을 실행하는 경우 잠정적으로 다른 라이브러리로 대체할 수 있다). 리눅스에서 LD_LIBRARY_PATH 는 표준 디렉토리 집합에 앞서 우선적으로 라이브러리가 검색되는 콜론으로 분리된 디렉토리 집합이다; 이는 새로운 라이브러리 디버깅 또는 특별한 목적을 위한 비표준 라이브러리 사용할 때 유용하지만 이러한 디렉토리를 제어할 수 있는 해당 사용자가 이들을 신뢰해야 함을 명심해라. LD_RELOAD 변수는 /etc/ld.so.preload 파일이 하는 것처럼 표준 집합을 재정의하는 함수들을 갖는 객체 파일을 열거한다. LD_DEBUG 변수는 디버깅 정보를 보여준다; ``all" 로 설정된다면 디버깅시에 동적 링크 프로세스에 대한 방대한 정보를 보여준다.

사용자가 동적 링크 라이브러리를 제어할 수 있게 허용하는 것은 특별한 조치를 취하지 않는다면 setuid/setgid 프로그램의 경우 매우 위험할 것이다. 따라서 GNU glibc 구현에서 setuid 또는 setgid 프로그램의 경우 이러한 변수 (또는 다른 유사한 변수) 는 무시되거나 그들이 할 수 있는 것이 제한된다. GNU glibc 라이브러리는 프로그램의 credentials 을 검사함으로써 setuid 또는 setgid 프로그램인지를 결정한다; uid 와 euid 또는 gid 와 egid 가 다른 경우 라이브러리는 setuid/setgid 프로그램 (또는 이러한 프로그램의 자손) 이라고 간주해서 링크를 제어할 수 있는 능력을 매우 제한한다. GNU glibc 라이브러리를 적재한다면 이러한 현상을 볼 수 있다; 특히 elf/rtld.c 와 sysdeps/generic/dl-sysdep.c 파일을 보라. 이는 uid 와 gid 를 euid 와 egid 와 같게 만들어서 프로그램을 호출하는 경우 이러한 변수들이 최대한 영향을 미칠 것임을 의미한다. 다른 유닉스 계열 시스템은 이 상황을 다르지만 동일한 이유로 다룬다: setuid/setgid 프로그램은 환경 변수 셋에 의해 부당하게 영향을 받지 않아야 한다.

리눅스 시스템에 대해서 저자가 작성한 문서인 Program Library HOWTO 에서 더욱 자세한 정보를 얻을 수 있다.