PID=1인 initramfs 내에서 대화형 busybox 쉘을 실행하는 방법

PID=1인 initramfs 내에서 대화형 busybox 쉘을 실행하는 방법

배경

내 자신의 initramfs를 어셈블해야 하며 init 스크립트를 작성하기 전에 필요한 모든 작업을 수동으로(즉, 대화형 셸에서) 수행하고 싶습니다. 내 선택은 모든 작업에 대해 busybox를 정적으로 연결하는 것입니다.

내가 하는 일

initramfs /bin에 비지박스 실행 파일이 있고, /bin: 'sh' -> /bin/busybox에 있는 셸에 대한 심볼릭 링크가 있고, initramfs 루트에 /bin/sh에 대한 init 심볼릭 링크가 있습니다.

내가 얻는 것

busybox는 이제 이름이 다음과 같다고 생각 init하고 Enter 키를 누른 후 프롬프트를 표시합니다 Please press Enter to activate this console.. 쉘에 들어가지만 PID가 1이 아닙니다. PID=1인 프로세스는 입니다 init. 그래서 수동으로 할 수 없고 switch_root메인 시스템 부팅을 계속할 수 없습니다.

성공적으로 initramfs에서 bash를 쉘로 실행해 보았습니다. PID=1로 실행되었고 실행이 허용되었습니다 switch_root.

질문

initramfs에서 PID=1인 대화형 busybox 쉘을 어떻게 실행합니까?

답변1

TLDR 답변

init이미 발견한 바와 같이 프로그램을 선택한 쉘(initramfs에서)에 간단히 심볼릭 링크함으로써 이를 수행할 수 있습니다 .

"Busy Box" 문제

직면하고 있는 문제는 busybox "기능"입니다. Busybox는 컴파일 타임에 포함하기로 선택한 모든 유틸리티를 단일 범용 실행 파일로 패키징합니다. 그런 다음 심볼릭 링크 이름(예: 벡터)을 기반으로 argv[0]실행 시 "하위 유틸리티"를 시작합니다 .

이 기술을 사용하면 모든 유틸리티를 정적으로 링크할 수 있습니다(DLL이라고도 불리는 dylib가 필요하지 않음 - 매우 강력함). 손상된 libc(glibc와 같은)로 인해 비지박스가 작동하지 않는 일은 절대 없습니다. 그러나 컴파일된 코드를 공유할 수 있습니다. 모든 유틸리티가 단일 실행 파일에 있기 때문에 모든 유틸리티는 동일한 공유 함수(예: 실행 파일 strlen) 를 직접 호출할 수 있습니다 printf. 즉, 실행 파일 하위 유틸리티의 함수 코드는 서로 공유됩니다. 모든 유틸리티를 DLL에 있는 것처럼 저장하고 저장 공간을 절약합니다(모든 유틸리티/명령을 단일 파일에 포함하는 비지박스 바이너리 하나만 필요하므로 모든 유틸리티 프로그램은 동일한 ELF 헤더 및 기타 ELF 형식 구조를 공유하며 해당 실행 파일의 기능 - 수십 개의 개별 실행 파일과 마찬가지로 전체 결과를 더 작게 만듭니다. 심볼릭 링크는 장치에서 더 많은 공간을 차지합니다. 유틸리티 실행 파일의 다중 ELF 구조는 더 적은 공간을 차지합니다.

lsbusybox는 이제 실행 시 argv 벡터의 0번째 위치를 확인 ["busybox", "ls"...]하거나 확인하여 ["ls",..]실행할 하위 유틸리티를 결정합니다 .

이전 기호 링크가 올바르게(즉, $PATH에) 배치된 경우 즉, ln -s busybox ls ; ./ls실행하는 것과 동일하며 busybox ls실행하는 것은 실행하는 것과 같습니다.ls

심볼릭 링크 이름이 로 지정되면 커널에 의해 initbusybox의 벡터로 전달되며 , 이는 busybox가 호출되는 것을 "확인"하여 실제 프로그램 하위 유틸리티로 시작되는 이름입니다.argv[0]init

해결책

문제를 해결하려면 다음과 같이 하면 됩니다.

  • 텍스트 파일 생성/bin/init
  • 실행 가능으로 표시
  • 다음과 같이 코드를 작성하십시오.
#!/bin/sh
exec /bin/sh # this should replace current init process which is the sh interpreter from shebang above but with arg[0] of `init` with sh interpreter with argv[0] of `sh` - and this should be enough, to make busybox believe it should run `sh` sub-utility, which will end as PID1 because of `exec` in front.

sh간단히 말해서, 비지박스가 자신의 이름을 딴 프로세스로 실행되고 쉘처럼 동작하도록 설득해야 합니다 .

내 경험에 따르면 임시 initramfses 및 init 시나리오를 개발할 때 /bin/init실제 init 구현을 가리키고 2개의 부트로더 메뉴를 정의하는 것이 더 효율적입니다.

  • 메뉴 항목 1: 내 초기화로 시작
  • init=/bin/sh메뉴 항목 2: 커널 명령줄에 LAST 매개변수를 추가하여 쉘 사용을 시작합니다.

이렇게 하면 bootloader/qemu 등에서 원하는 메뉴 항목을 선택하기만 하면 부팅 모드(테스트 실행, 수동)를 선택할 수 있습니다.

관련 정보