Diary

Diary

日々学んだことをアウトプットする場として初めてみました

どうしてもヌルバイトを使用したい

どうしてもヌルバイト (NUL) を出力・使用したいことがあったで、その時の出し方についてメモしておきます。

[目次]

ヌルバイトとは

ヌルバイト (Null Byte) は、値が0のバイトであり、C 言語では文字列の終端を示すために使われる特別な文字コードです。

こんなやつ 『わーい』

ASCIIコードではヌルバイトは文字コードの 0 番目に対応し、表記ではしばしば \0 として表されます。

ヌルバイトは見えない文字であるため、テキストエディタや標準のコンソール出力では通常は表示されません。 しかし、ヌルバイトを含む文字列を処理する場合は、それが意図した挙動をするかどうかを確認する必要があります。 例えば、ヌルバイトを含む文字列を出力しようとした場合、多くのツールやプログラムはヌルバイトに到達すると文字列が終了したと見なし、それ以降を無視することが多いです。

これが悪用された脆弱性などもあるため、今一度確認しておきたいです。 (とはいえ今時は大丈夫だったりする?)

ターミナルからの出力

ここでは echo と printf を使ってヌルバイトを出力させてみます。

# echo のユニコードエスケープシーケンスで \u0000 と打つ。
echo -e "\u308f\u30fc\u0000\u3044"
わーい

# printf を使って \00 で出す。
printf 'わー\00い' 
わーい

しかし前述したようにコンソール出力では通常無視されるため、目視・コピーでは付いてきません

そこで次のどちらかの方法で回避することが可能です。

printf 'わー\00い' >> tmp-wa-i

printf 'わー\00い' | clipcopy

どんな問題が?

自分もあまり分かってませんが、遭遇した問題点を挙げておきます。

db: postgresql

golang で pq というドライバを使って postgresql にデータを投入しようとした際に、text のデータ型の部分にヌルバイトが入っていた場合、以下のようなエラーを吐いて INSERT に失敗しました。

pq: invalid byte sequence for encoding "UTF8": 0x00

コマンドの結果が期待値とならない

結構色んなコマンドで困りごとが出てきそうです。

# NUL が終端となってるため、それ以降が処理されない。
# F とか変えても無理そう。
$ echo -e "\u308f\u30fc\u0000\u3044" | awk '{print $0}'
わー


# xargs
echo -e "\u308f\u30fc\u0000\u3044" | xargs echo
わー

# このケースは option で乗り切れそう。
## mac
$ echo -e "\u308f\u30fc\u0000\u3044" | xargs -0 echo
わー い
## linux (gnu)
$ echo -e "\u308f\u30fc\u0000\u3044" | xargs --null echo
わー い

シェル設定によってはセパレーターになってる

シェルの設定によってはヌルバイトがセパレーター (デリミター) になってるケースがあります。 ターミナルでの操作は基本行ベースで楽しんでるかと思うのですが、そこに意図しないヌルバイトがあると意図した結果にならないことがあります。 (と思ったのですが、これに直接起因した問題を提示することができませんでした。。。)

# mac, zsh
# スペース、水平タブ、改行、ヌルバイト が IFS (Internal Field Separator) として設定されている。
$ echo -n $IFS | hexdump -C
00000000  20 09 0a 00                                       | ...|
00000004

# linux, bash
# IFS は設定されていない。
# しかし man bash には『<space><tab><newline>』がデフォルトになりそうなことが書いてる。
$ echo -n $IFS | hexdump -C