Bash가 Alpine 3.14.2에서 실행 가능 비트를 올바르게 평가하지 못하는 이유는 무엇입니까?

Bash가 Alpine 3.14.2에서 실행 가능 비트를 올바르게 평가하지 못하는 이유는 무엇입니까?

Bash 5.1.4(1)를 실행하는 dockerized Alpine 3.14.2에서 Bash 스크립트에서 이상한 동작이 발생합니다. 가장 중요한 것은 파일의 실행 가능성을 테스트하는 것이지만 항상 실패합니다. 간단히 말해서 이것은 if 테스트입니다.

bash-5.1# if [ ! -x /opt/java/openjdk/bin/java ]; then echo "something strange just happened"; fi
something strange just happened

그러나 내가 알고 있는 실행 가능성을 "테스트"하는 다양한 방법은 모두 다양한 결과를 보여줍니다.

bash-5.1# ls -la /opt/java/openjdk/bin/java
-rwxr-xr-x    1 root     root         12648 Jan 21  2021 /opt/java/openjdk/bin/java
bash-5.1# stat -c "%A" /opt/java/openjdk/bin/java
-rwxr-xr-x
bash-5.1# /opt/java/openjdk/bin/java --version
openjdk 15.0.2 2021-01-19
OpenJDK Runtime Environment AdoptOpenJDK (build 15.0.2+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 15.0.2+7, mixed mode, sharing)

내 스크립트가 제대로 작동하려면 Bash 내의 실행 가능성 테스트가 올바른 결과를 반환해야 합니다.그런데 왜 안되죠?

제가 확인하거나 시도한 내용이 많이 있습니다. 그중 일부는 커뮤니티 제안을 바탕으로 한 것입니다.

  • 모든 (테스트된) 실행 파일에 대한 검사가 실패했습니다. Bash 자체도 마찬가지입니다. 결과는 항상 잘못되었습니다.
bash-5.1# if [ ! -x /bin/bash ]; then echo "this is weird"; fi
this is weird
  • @KamilMaciorowski는 자신의 의견에서 bash 적용 범위 테스트를 제안했습니다. 그러나 출력은 괜찮아 보입니다.
bash-5.1# type -a [
[ is a shell builtin
  • 다음은 명령의 추적입니다(@zevzek에게 감사드립니다).
bash-5.1# strace -fe trace=access,faccessat,stat bash -c '[ -x /bin/bash ]'
stat("/root", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat(".", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat("/root", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat("/root", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat(".", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
stat("/usr/local/sbin/bash", 0x7ffc257ec050) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/bash", 0x7ffc257ec050) = -1 ENOENT (No such file or directory)
stat("/usr/sbin/bash", 0x7ffc257ec050)  = -1 ENOENT (No such file or directory)
stat("/usr/bin/bash", 0x7ffc257ec050)   = -1 ENOENT (No such file or directory)
stat("/sbin/bash", 0x7ffc257ec050)      = -1 ENOENT (No such file or directory)
stat("/bin/bash", {st_mode=S_IFREG|0755, st_size=760136, ...}) = 0
stat("/bin/bash", {st_mode=S_IFREG|0755, st_size=760136, ...}) = 0
+++ exited with 1 +++
  • Busybox에서 "real"을 사용하면 문제가 없지만 Bash에서는 [작동하지 않습니다 . [하지만 이 컨테이너의 소프트웨어와 함께 제공되는 모든 Bash 스크립트를 다시 작성하는 것은 불가능합니다.
bash-5.1# which [
/usr/bin/[
bash-5.1# if [ ! -x /bin/bash ]; then echo "this is weird"; fi
this is weird
bash-5.1# if /usr/bin/[ ! -x /bin/bash ]; then echo "this is weird"; fi
bash-5.1#
  • 파일 시스템이 "noexec" 마운트되지 않음(예: /proc 등 예상하는 파일 시스템만 마운트)

  • 다른 테스트는 [ -f /bin/bash ]정확[ -f /tmp/not_there ] 하지만 단지 -x잘못된 것처럼 보입니다.

  • Bash 5.1.1을 사용해 보았는데 거기서 작동합니다. 그때 내가 경험했어배쉬 릴리스 노트, 하지만 둘 사이에 관련된 내용을 찾을 수 없습니다.

답변1

Alpine 3.14는 여기에서 알려진 버그와 관련된 것으로 보입니다. 모든 기술적 세부 사항은 이미해결되지 않은 문제가 있습니다(처음에는 "실행 가능" 비트를 찾고 있었기 때문에 찾지 못했습니다.)

즉, 아직은 Alpine 3.14에서 Bash를 사용하지 마세요.

긴 대답은 영향을 받는 특정 구성 요소 집합을 업데이트하는 것인데, 이는 Docker 환경에서 대부분의 경우 비실용적입니다.

관련 정보