문자열 비교는 느리지만 인덱싱은 빠르며, 제가 작성하는 많은 스크립트가 bash에 있기 때문에 질문합니다. bash는 제가 아는 한 모든 실행 가능한 호출에 대해 전체 문자열 조회를 수행합니다. 이러한 모든 ls
' 및 grep
'는 각 단계에서 문자열 조회를 수행하지 않고도 조금 더 빨라질 것입니다. 물론 이제 컴파일러 최적화를 탐구합니다.
어쨌든 inode 번호만 사용하여 Linux에서 프로그램을 직접 호출할 수 있습니까(모든 호출에 대해 한 번만 조회하면 된다고 가정)?
답변1
가장 간단한 대답은 '아니요'입니다.
더 긴 답변은 Linux 사용자 API가 inode 번호를 사용하여 파일에 액세스하는 방법을 지원하지 않는다는 것입니다. inode 번호에 대한 유일한 액세스는 일반적으로 inode 번호를 노출하는 stat() 시스템 호출을 통해서입니다. 이는 두 파일 이름이 동일한 파일인지 식별하는 데 유용하지만 다른 것에는 유용하지 않습니다.
inode를 통해 파일에 액세스하면 inode에 연결된 파일이 포함된 디렉터리의 권한을 우회하므로 보안을 위반합니다.
가장 가까운 방법은 파일 핸들을 열어 파일에 액세스하는 것입니다. 그러나 여기서도 프로그램을 실행할 수 없으며 여전히 경로를 통해 파일을 열어야 합니다. (설명에서 언급했듯이 이 기능은 보안상의 이유로 *at 시스템 호출의 나머지 부분과 함께 Linux에 추가되었지만 이식 가능하지는 않습니다. (표준은 계속 발전하고 있습니다.)
inode 번호를 사용하여(기본적으로 파일 시스템을 잡고 stat를 사용하여) 파일을 찾은 다음 정상적으로 실행하는 방법도 있지만 경로 이름을 통해 파일에 액세스하는 것보다 비용이 훨씬 더 많이 들기 때문에 이는 원하는 것과 반대입니다. 그 비용을 제거하지 마십시오.
하지만 Linux는 이미 내부 inode 조회에 대해 많은 최적화를 수행하므로 이러한 유형의 최적화에 대해 걱정할 필요가 거의 없습니다. 또한 쉘은 전통적으로 실행 파일의 경로 위치를 해시하므로 $PATH
매번 모든 디렉터리에서 해당 파일을 찾을 필요가 없습니다 .
답변2
예가능한파일의 inode를 통해 파일을 실행합니다.
find / -inum 242 -exec {} \; -quit
그러나 성능이 문제가 되며 위의 내용은 성능이 아닙니다. 해당 inode가 있는 파일(여러 개가 있을 수 있음)을 찾기 위해 디렉토리 구조를 탐색할 뿐만 아니라, 뒤에서는 inode 번호가 경로로 확인되고 해당 경로가 실행을 위해 커널에 제공됩니다. 그런데 왜?
커널은 모두 커널 함수를 래핑하는 일련의 exec 함수( 등)를 노출 execl
합니다 . 현재 프로세스 이미지를 내용을 읽어 부팅된 새로운 프로세스 이미지로 교체하는 기능입니다.execvp
execve
주어진 파일 경로에서. 그래서모든커널에서 제공하는 프로그램의 실행 방법을 경로를 통해 알려주어야 합니다. 파일 경로를 진입점으로 사용하면 파일 경로와 관련된 모든 액세스 제어 이점을 얻을 수 있으므로 "경로별" API는 Linux에서 프로그램 실행을 위한 유일한 API입니다.
그러나 번거롭고 모든 환경에서 작동이 보장되지 않는 메커니즘이 있으므로 프로그램을 호출할 수 있습니다.기억으로부터. 메모리에 있는 모든 것은 디스크에 있는 것보다 빠르기 때문에 프로그램을 최대한 빨리 실행하는 방법이 문제의 핵심이 됩니다.
2002년 초, (유명한) 해커 grugq가 userland exec 개념을 도입했습니다. 이것은 쉘 함수가 아닙니다 . 사용자 모드에서 작성된 커널 함수에 의해 수행되는 모든 단계의 시뮬레이션 exec
입니다 . execve
이는 일반적인 액세스 제어 메커니즘 외부에서 프로그램 실행을 허용하므로 자신의 활동을 숨기고 싶은 해커에게 이상적입니다 execve
.
이 메서드를 구현하려면 주소 공간 정리, 동적 링커 로드(필요한 경우), 스택 초기화 등을 수행하는 여러 도우미가 필요합니다. 또한 메커니즘을 사용하려면 필요한 코드를 특정 유형의 메모리에 로드해야 합니다.
이런 일을 어렵게 만드는 대책도 있지만, 불가능한 것은 아니다. 필요한 것은 대상 시스템에 페이지 정렬 메모리, 메모리를 실행 가능으로 표시하는 기능, 메모리의 특정 지점으로 점프하는 기능이 있다는 것입니다. 이러한 요구 사항은 일반적으로 다음과 같이 해석됩니다. 이를 C로 작성하고 SELinux가 없거나 SELinux가 완전히 활성화되지 않은 시스템에서 사용해야 합니다. 여기서는 구현 세부 사항을 논의하지 않지만 직접 탐색할 수 있는 링크를 제공할 것입니다.
따라서 Linux 시스템이 위의 요구 사항을 충족하는 경우 다음과 같은 방법으로 메모리에서 코드를 실행할 수 있습니다.
- 코드를 메모리의 한 위치에 로드합니다. 초기 제거의 일부로 악의적인 행위자가 필요한 코드를 메모리에 사이드로드했지만 inode 방식으로 수행하려는 경우 다음을 수행할 수 있습니다.
find / -inum 242 -exec cat {} \;
- userland exec 메커니즘을 호출하여 진입점을 1단계에서 프로그램을 저장한 메모리 주소로 설정합니다.
- 이익
커널, 파일 시스템 및 셸은 모두 조정되어 프로그램 조회 및 실행이 작업을 수행하는 데 필요한 총 오버헤드의 작은 부분입니다. 메모리에 프로그램을 로드하고 거기에서 실행하는 것은 실제로 평균 사용 사례의 범위에 포함되지 않으므로 재미로 수행하는 것이 아니라면 시도하는 데 시간을 투자하기 전에 성능을 벤치마킹해야 한다고 말하고 싶습니다. .
인용하다:
답변3
이는 i-node 질문에 대한 직접적인 대답은 아니지만 쉘 스크립트에서 표준 유틸리티 경로를 찾는 것을 방지할 수 있는 방법입니다.
바쁜 상자많은 표준 Unix 유틸리티를 대체하는 모든 도구를 합친 크기보다 훨씬 작은 단일 실행 파일로 결합한 프로그램입니다. 이는 디스크 크기가 매우 중요한 임베디드 세계에서 매우 인기가 있습니다. 일반적인 BusyBox 기반 시스템에서 , sh
및
ls
는 grep
모두 에 대한 심볼릭 링크입니다 busybox
. 따라서 ls
호출하는 쉘 스크립트는 자신을 두 번만 호출 grep
합니다 busybox
.
BusyBox에는 "독립형 쉘"이라는 실험적 기능이 있습니다. 이 기능이 활성화되면 셸 역할을 하는 BusyBox는 구현하는 유틸리티에 대한 경로 조회를 수행하지 않습니다. 대신 /proc/self/exe
올바른 매개변수를 사용하여 자체적으로 실행됩니다. 예를 들어 를 호출하는 쉘 스크립트를 실행하는 경우 를 grep
찾는 대신 실행됩니다 . 커널에는 여전히 경로 조회가 있지만 어떤 유틸리티를 호출하든 항상 동일하며 실행 가능한 이미지가 이미 메모리에 있으므로 로드할 필요가 없습니다.grep
$PATH
/proc/self/exe grep <arguments>
/proc/self/exe
그러나 BusyBox에는 많은 최적화 기능이 있습니다.사이즈별속도보다는 몇 마이크로초를 절약하는 데 관심이 있다면 아마도 최선의 선택이 아닐 것입니다. 또한 앞서 언급한 것처럼 "독립형 쉘" 기능은 실험적이라고 표시되어 있습니다.
답변4
노드 번호만 사용하여 Linux에서 프로그램을 직접 호출하는 방법이 있습니까?
아니요, 그렇지 않습니다. 단순한 이유 때문에 단수형을 사용하고 있습니다.ㅏ계획"과 "그것은inode 번호"를 사용하지만 inode는 고유하지 않습니다. 시스템에 동일한 inode 번호를 가진 파일이 여러 개 있을 수 있습니다.
따라서 간단한 상식에 기초하여 할 수 있는 최선의 방법은 "inode 번호만을 사용하여 하나 이상의 프로그램 세트를 직접 호출"하는 것입니다.할 수 없다옮기다특정한프로그램 그룹에서 프로그램을 선택하기 위해 해당 프로그램에 대한 추가 식별 정보를 요구하지 않고 프로그램.
물론 식별 정보 중 하나는 경로일 수 있습니다. 이 시점에서 다시 원점으로 돌아갑니다.