In a dockerized Alpine 3.14.2 running Bash 5.1.4(1), I encountered a strange behaviour in a Bash script. The essential line is a test for executability of a file, which always fails. This is the if test in a nutshell:
bash-5.1# if [ ! -x /opt/java/openjdk/bin/java ]; then echo "something strange just happened"; fi
something strange just happened
But, the numerous ways I know of to "test" executability all show a different result:
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)
In order to get my script working, the executability test inside Bash should return the proper result. But why doesn't it?
There is a rather long list of things I checked or tried out, some of them after suggestions from the community:
- The check fails all (tested) executables. Even Bash itself. The result is always wrong:
bash-5.1# if [ ! -x /bin/bash ]; then echo "this is weird"; fi
this is weird
- @KamilMaciorowski suggested to test for bash overrides in his comment. But the output seems fine:
bash-5.1# type -a [
[ is a shell builtin
- This is a strace on the command (thanks @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 +++
- Using the "real"
[from Busybox works fine, but not using[in Bash. But I can't possibly rewrite all Bash scripts shipped with software in that container:
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#
The filesystem is not mounted "noexec" (only the ones you would expect, like /proc)
Other tests like
[ -f /bin/bash ]or[ -f /tmp/not_there ]are correct, only-xseems brokenI tried Bash 5.1.1 and it worked there. I then went through the Bash release notes, but I can't find anything relevant in between.
adoptopenjdk/openjdk15-openj9:x86_64-alpine-jre-15.0.2_7_openj9-0.24.0(1a455cef4162) afterapk add bash.noexecby any chance?