mainThe GNU Bourne-Again SHell - Support: sr #110744, bash 5.2 refuses to execute binary...


sr #110744: bash 5.2 refuses to execute binary shell scripts

Submitter:  None
Submitted:  Tue 18 Oct 2022 05:57:20 PM UTC
Category:  None Priority:  5 - Normal
Severity:  3 - Normal Status:  Done
Privacy:  Public Assigned to:  None
Originator Email:  -email is unavailable- Open/Closed:  Open
Operating System:  GNU/Linux
* Mandatory Fields

Add a New Comment Rich Markup

Jump to the original submission

Sun 06 Nov 2022 01:22:23 AM UTC, comment #10: 

Awesome. I was looking in the "master" branch missed the devel branch.

Thanks for putting it in so quickly!

Sat 05 Nov 2022 05:02:18 PM UTC, comment #9: 

There is already a change in the bash devel git branch. You could open a bug report with your preferred vendor and ask them to adopt it.

Chet Ramey <chet>
Group administrator
Sat 05 Nov 2022 12:01:17 AM UTC, comment #8: 

What should I do next? :)

Should I submit a patch?

Mon 24 Oct 2022 02:22:11 PM UTC, comment #7: 

I like it.

Chet Ramey <chet>
Group administrator
Fri 21 Oct 2022 11:44:03 PM UTC, comment #6: 

I do not know to submit a patch for bash, perhaps something like this:

diff --git a/general.c b/general.c
index 85c5a8b6..9658d704 100644
--- a/general.c
+++ b/general.c
@@ -681,21 +681,23 @@ check_binary_file (sample, sample_len)
      int sample_len;
   register int i;
+  int nlines;
   unsigned char c;

   if (sample_len >= 4 && sample[0] == 0x7f && sample[1] == 'E' && sample[2] == 'L' && sample[3] == 'F')
     return 1;

   /* Generally we check the first line for NULs. If the first line looks like
-     a `#!' interpreter specifier, we just look for NULs anywhere in the
-     buffer. */
+     a `#!' interpreter specifier, we look for NULs in the first two lines. */
   if (sample[0] == '#' && sample[1] == '!')
-    return (memchr (sample, '\0', sample_len) != NULL);
+    nlines = 2;
+  else
+    nlines = 1;

   for (i = 0; i < sample_len; i++)
       c = sample[i];
-      if (c == '\n')
+      if (c == '\n' && --nlines == 0)
         return (0);
       if (c == '\0')
         return (1);

Thu 20 Oct 2022 08:37:35 PM UTC, comment #5: 

Your compromise makes sense a lot of sense.
That way the script can give another executable (java in this case) the opportunity to use the script file (binary or not) as input.

Thu 20 Oct 2022 07:57:38 PM UTC, comment #4: 

See for the discussion that prompted this change.

Chet Ramey <chet>
Group administrator
Thu 20 Oct 2022 07:52:27 PM UTC, comment #3: 

How about this as a compromise:

The intent is to skip over an initial `#!' line, since that is going to be ASCII in just about every case. So what we can do is skip that line, then check the next line for NULs, as we would do if the `#!' line were not present.

That should satisfy your requirements and mine.

As to your questions, it's an implementation quality and user experience feature. No one wants to see bash trying to execute binary data as commands, producing garbage results and possibly messing up the user's terminal, so we check for NULs as an indicator. Just about every shell does something similar, and POSIX says the shell can throw an error on binary data, period.

If you want to include a NUL as part of a string, use $'\0'. Note that bash uses C strings, so it will treat the NUL as a string terminator.

Chet Ramey <chet>
Group administrator
Wed 19 Oct 2022 05:11:40 PM UTC, comment #2: 

Thanks Chet.

> Yes, the previous logic was in error. Bash doesn't want to execute scripts containing binary data.

Is that for security reasons? What if I wanted to include an unescaped string or something else binary in a file?

> How would you suggest satisfying that requirement while still allowing these self-executing jar files you want?

Honestly I don't know. Jar files are binary by nature.

Of course one can always have a separate shell script along the jar, that trivially works, but it less convenient.

Or one might be able to handle this with "file magic"

Note that I can still make this work if I add a new-line to the beginning of the file. In that case bash will happily execute the binary file, which, I think, is not intended.

Wed 19 Oct 2022 02:57:09 PM UTC, comment #1: 

Yes, the previous logic was in error. Bash doesn't want to execute scripts containing binary data.

Consider the behavior of the script you've included below. It
ends up being called as

/bin/bash ./

but if you only check the first line for binary characters, and
that first line is a #! line, you can miss binary scripts.

How would you suggest satisfying that requirement while still allowing these self-executing jar files you want?

Chet Ramey <chet>
Group administrator
Tue 18 Oct 2022 05:57:20 PM UTC, original submission:  

Steps to Reproduce:

$ cat <<EOF >
echo 'x'
$ chmod +x
$ ./
$ head -c 1 /dev/zero >>
$ ./
./ ./ cannot execute binary file

This worked fine in bash 5.1.x. It looks like this is per design now (per the changes in general.c)

There are reasons to allow this. For example a common way to create an executable jar file in Java is the following:

$ cat <<EOF > exec.jar

exec java -Xmx1G -jar "$0" "$@"

$ chmod +x exec.jar
$ cat non-exec.jar >> exec.jar

Now you have an executable jar. But in bash 5.2 this would no longer execute.

Thanks and Cheers.



(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

No files currently attached


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by chet (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.


    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2022-10-24 chet StatusIn Progress Done
    2022-10-19 chet StatusNone In Progress

    Back to the top

    Powered by Savane 3.13-4b48.
    Corresponding source code