8

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 -x seems broken

  • I 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.

3
  • 1
    Could not reproduce on adoptopenjdk/openjdk15-openj9:x86_64-alpine-jre-15.0.2_7_openj9-0.24.0 (1a455cef4162) after apk add bash. Commented Sep 30, 2021 at 9:33
  • 1
    @gendergap Indeed, when asked for clarifications, please don't place them in the comment section but edit the question instead, so that any contributor has all relevant informations immediately at a glance. Reading through the comment section on the other hand is cumbersome, and comments are subject to removal by moderators without notice. Commented Sep 30, 2021 at 11:20
  • 2
    Is the filesystem mounted noexec by any chance? Commented Sep 30, 2021 at 12:21

1 Answer 1

7

It seems as though Alpine 3.14 is pertinent to a known bug here. All the technical details are part of an already open issue there (which I initially did not find because I was always looking for the "executable" bit).

The short answer is to not use Bash in Alpine 3.14 for the time being.

The long answer would be to update the specific set of affected components, which in a Docker context is impractical most of the time.

4
  • "This is related to faccessat2 syscall has been enabled in musl in alpine starting 3.14. Due to a bug in runc it fails if your kernel do not support faccessat2." -- oopsie! Yep, that would cause some chaos. Also might explain why the strace doesn't show the call to faccessat()... Commented Sep 30, 2021 at 13:45
  • That part is way beyond my knowledge! But yes, it seems you were on the right track there. Kudos! Commented Sep 30, 2021 at 13:49
  • not really, just on a track that looked similar. I was thinking about it being a bug, though, but had no clue at all as to what could cause a bug like that... Commented Sep 30, 2021 at 13:59
  • 1
    BTW, it looks like this question and answer pair is your first contribution to the site. Quite successful debut. Way to go! Commented Oct 1, 2021 at 6:19

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.