Bash

是否允許 shell 忽略腳本中的 NUL 字節?

  • November 27, 2019

因為這就是他們中的一些人正在做的事情。

> echo echo Hallo, Baby! | iconv -f utf-8 -t utf-16le > /tmp/hallo
> chmod 755 /tmp/hallo
> dash /tmp/hallo
Hallo, Baby!
> bash /tmp/hallo
/tmp/hallo: /tmp/hallo: cannot execute binary file
> (echo '#'; echo echo Hallo, Baby! | iconv -f utf-8 -t utf-16le) > /tmp/hallo
> bash /tmp/hallo
Hallo, Baby!
> mksh /tmp/hallo
Hallo, Baby!
> cat -v /tmp/hallo
#
e^@c^@h^@o^@ ^@H^@a^@l^@l^@o^@,^@ ^@B^@a^@b^@y^@!^@
^@

這是標準實際要求的一些兼容性問題嗎?因為它看起來非常危險和意外。

根據POSIX

輸入文件應為文本文件,但行長不受限制¹

輸入中的 NUL 字元²使其成為 non-text,因此就 POSIX 而言,行為是未指定的,因此sh實現可以做任何他們想做的事情(並且符合 POSIX 的腳本不得包含 NUL)。

有些 shell 會掃描前幾個字節的 0 並拒絕執行腳本,假設您錯誤地嘗試執行非腳本文件。

這很有用,因為如果系統在 上返回 ENOEXEC,則需要exec*p()函式、env命令、shfind -exec來呼叫 shell 來解釋命令,因此,如果您嘗試為錯誤的架構執行命令,最好獲得勝利’不要從你的 shell 執行一個二進製文件錯誤,而不是 shell 試圖將它理解為一個 shell 腳本。execve()

這是 POSIX 允許的:

如果執行檔不是文本文件,shell 可能會繞過此命令執行。

在標準的下一次修訂中將更改為

shell 可以應用啟發式檢查來確定要執行的文件是否可以是腳本,並且如果它確定文件不能是腳本,則可以繞過此命令執行。在這種情況下,它應寫入錯誤消息,並應返回退出狀態 126。

注意:拒絕不能是腳本的文件的常見啟發式方法是在固定長度內的 <newline> 字節之前定位 NUL 字節文件的前綴。由於 sh 需要接受具有無限行長度的輸入文件,因此啟發式檢查不能基於行長度。

這種行為可能會妨礙 shell 自解壓存檔,儘管其中包含一個 shell 標頭,後跟二進制數據¹。

Shell 在其zsh輸入中支持 NUL,但請注意 NUL 不能在 的參數中傳遞execve(),因此您只能在參數或內置命令或函式的名稱中使用它:

$ printf '\0() echo zero; \0\necho \0\n' | zsh | hd
00000000  7a 65 72 6f 0a 00 0a                              |zero...|
00000007

(這裡定義和呼叫一個以 NUL 為名稱的函式,並將 NUL 字元作為參數傳遞給內置echo命令)。

有些人會剝離它們,這也是明智的做法。NULs 有時用作填充。例如,它們會被終端忽略(有時它們會被發送到終端以讓它們有時間處理複雜的控制序列(如輸入(字面意思))。文件中的空洞似乎被 NUL 填充,等等。

請注意,非文本不限於 NUL 字節。它也是在語言環境中不形成有效字元的字節序列。例如,0xc1 字節值不能出現在 UTF-8 編碼文本中。因此,在使用 UTF-8 作為字元編碼的語言環境中,包含此類字節的文件不是有效的文本文件,因此也不是有效的sh腳本³。

實際上,yash它是我所知道的唯一一個會抱怨這種無效輸入的 shell。


¹ 在標準的下一次修訂中,它將更改

輸入文件可以是任何類型,但要根據 shell 語法(XSH 2.10.2 Shell 語法規則的 XREF)解析的文件的初始部分應由字元組成,並且不應包含 NUL 字元。外殼不應強制執行任何行長度限制。

明確要求 shell 支持以沒有 NUL 字節的語法有效部分開頭的輸入,即使其餘部分包含 NUL,以解釋自解壓檔案。

² 和字元旨在根據語言環境的字元編碼進行解碼(參見 的輸出locale charmap),在 POSIX 系統上,NUL 字元(其編碼始終為字節 0)是唯一編碼包含字節 0 的字元。在其他換句話說,UTF-16 不屬於可以在 POSIX 語言環境中使用的字元編碼。

³ 然而,腳本中存在語言環境更改的問題(例如分配LANG/ LC_CTYPE/ LC_ALL/LOCPATH變數時),以及何時更改對解釋輸入的 shell 生效。

引用自:https://unix.stackexchange.com/questions/554176