(评论)
(comments)

原始链接: https://news.ycombinator.com/item?id=43646698

Hacker News 讨论主要围绕类 Unix 系统中的 Shebang(`#!`)机制展开。一位用户提到了一个“空字节攻击”,其中空字节可以终止 Shebang 行,从而允许以非标准方式向解释器传递额外参数。另一位用户回忆起过去由于来自 Windows 系统的 Shebang 行中包含回车符(``)而导致的兼容性问题,这破坏了 Linux 上的脚本执行。 讨论随后转向 `binfmt_misc`,这是一个内核特性,允许通过文件扩展名或“魔数”(文件开头的字节序列)将非原生二进制文件(如 Java 的 JAR 文件)与特定解释器关联起来,从而执行它们。这使得运行编译后的可执行文件无需显式 Shebang。 文中举例说明,`binfmt_misc` 可以被配置为使 wine 解释器运行扩展名为 `.exe` 的可执行文件,无需额外配置,从而有效地实现了在 Linux 上无缝运行 Windows 可执行文件。

相关文章
  • 揭秘Shebang:内核探秘 2025-04-10
  • (评论) 2025-03-17
  • (评论) 2025-03-29
  • (评论) 2024-04-28
  • (评论) 2024-06-24

  • 原文
    Hacker News new | past | comments | ask | show | jobs | submit login
    Demystifying the (Shebang): Kernel Adventures (crocidb.com)
    26 points by thunderbong 1 hour ago | hide | past | favorite | 6 comments










    Fun fact: you can stick a null byte into the shebang line to terminate it, as an alterantive to the newline.

    It's possible to have a scripting language support extra command line arguments after the null byte, which is less disruptive to the syntax than recognizing arguments from a second line.

    I.e.

      #!/path/to/interpreter --arg--more --args
    
    Or

      #!/usr/bin/env interpreter--all --args
    
    On some OS's, you only get one arg: everything after the space, to the end of the line, is one argument.

    When we stick a there, that argument stops there; but our interpreter can read the whole line including the up to the and then extract additional arguments between and

    https://www.nongnu.org/txr/txr-manpage.html#N-74C247FD

    The interpreter could get the arguments in other ways, like from a second line after the hash bang line. But with the null hack, all the processing revolves around just the one hash bang line. You can retrofit this logic into an interpreter that already knows how to ignore the hash bang line, without doing any work beyond getting it to load the line properly with the embedded nul, and extract the arguments. You dont have to alter the syntax to specially recognize a hash bang continuation line.



    Less fun fact: you can't substitute a for .

    I had a Perl script (way) back in the day that came from a Windows system and it wouldn't work on Linux. After I figured out was causing the problem, I figured it out what bin_script (might have been in bin_misc) was doing wrong. bin_script sees "/bin/perl" and then fails to find that interpreter.

    So I proposed a one line change which fixed the glitch and posted it to LKML … and promptly got yelled at by Allan Cox for breaking compatibility. I dunno if the null byte breaks the same compatibility. Chapter and verse weren't cited.



    Read your article, it's really nice. I really feel much less demystified by this.

    But can you / somebody please explain what this means

    According to the official Kernel Admin Guide:

    This Kernel feature allows you to invoke almost (for restrictions see below) every program by simply typing its name in the shell. This includes for example compiled Java(TM), Python or Emacs programs. To achieve this you must tell binfmt_misc which interpreter has to be invoked with which binary. Binfmt_misc recognises the binary-type by matching some bytes at the beginning of the file with a magic byte sequence (masking out specified bits) you have supplied. Binfmt_misc can also recognise a filename extension aka .com or .exe.

    It’s another way to tell the Kernel what interpreter to run when invoking a program that’s not native (ELF). For scripts (text files) we mostly use a shebang, but for byte-coded binaries, such as Java’s JAR or Mono EXE files, it’s the way to go!

    Like, can you give me an example by what you mean. What are its use cases, if any. I read it many times and always with some sort of enthusiasm because of this sentence ending in exclamation point making me feel like it's huge yet I just can't understand it's significance.

    Does it mean we can have .jar files which can then run shebang like, so we don't need #! , can this also be used for main.go or every other language which has some issues with #! ,

    I see there being some interpreter for golang, rust etc. which just compiles it but it was just too complex. I am just imagining something like a simple go file which is valid golang but can be run by linux simply by ./ And it autocompiles it...



    Yes you can use binfmt_misc to allow arbitrary executable file format to be passed to an interpreter matched either by a filename extension or a magic number at a specific offset within the executable.

    https://en.wikipedia.org/wiki/Binfmt_misc



    The best and most common uses for this are Wine and qemu-static.

    For example, the following (which I grabbed from Wikipedia) `:DOSWin:M::MZ::/usr/bin/wine:` will register `/usr/bin/wine` to run as the wrapper for any .exe that gets executed, with no extra config needed. It simply sees that you tried to run a PE file and will run it in wine.



    Articles like this are just such a delight. History + common software + code snippets is a great combo






    Join us for AI Startup School this June 16-17 in San Francisco!


    Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact



    Search:
    联系我们 contact @ memedata.com