多くのLinuxディストリビューションで使用される標準的なCライブラリであるmusl libcにおいて、最近セキュリティ上の脆弱性が発見されました。これは、プログラミング言語の設計がいかにエンジニアリング文化やセキュリティに影響を与えるかを示す事例です。この欠陥は、同じ番兵値(センチネル値)であるアスタリスク(*)を、2つの異なるシステムが重複して使用したことによって発生しました。Unixシステムでは、歴史的に「*」というパスワードハッシュはロックされたアカウントを意味してきました。同時に、2012年以降、musl libcの`crypt`関数は、パスワードがハッシュ化するには長すぎる場合に文字列「*」を返すようになっていました。PAM(Pluggable Authentication Modules)を使用しない公式のAlpine AWSイメージなどを使用する特定のシステムでは、この組み合わせにより、未認証のユーザーがシェルを取得し、潜在的にルート権限を得ることが可能になっていました。
この問題はメモリ安全性のエラーではなく、C言語の技術的な制約に起因する論理的な欠陥でした。POSIX仕様では、`crypt()`は失敗した場合にヌルポインタを返し、エラーコードを設定することを要求しています。しかし、Cの型システムは開発者にヌルポインタのチェックを強制できないため、一部の開発者は仕様から外れることを選択しました。musl libcの開発者は、ヌルポインタをチェックしていないバイナリに対応するため、ヌルポインタの代わりに「*」という番兵値を返すことを選択したのです。これは「インバンド・シグナリング」の典型的な例であり、有効なデータの一部をエラー状態を伝えるために使用する慣行ですが、そのデータが別のシステムの論理と重複すると危険なものとなります。
対照的に、著者はRustのような言語が、その型システムとそれによって生じるエンジニアリング規範を通じて、このような事態を防ぐと主張しています。Rustは代数的データ型と「Result」型を利用しており、開発者に対してエラーのバリアントを明示的に処理することを強制します。Rustの環境では、長すぎるパスワードはエラーバリアントとして返されるため、呼び出し側がそれを成功したハッシュと誤認することは不可能です。さらに著者は、AI主導の開発時代においても、これらの言語固有の規範は極めて重要であると主張しています。LLMはメモリ安全性を推論でき、「安全な」言語の必要性を排除できると主張する者もいますが、著者はエージェントがいまだに言語のライブラリやコミュニティ標準にコード化された不変条件(インバリアント)に依存していることを指摘しています。C言語はビルド速度やニッチなアーキテクチャへの移植性において利点がありますが、より強力な型強制による規範を持つ言語への移行は、より決定論的なソフトウェアの厳格さへの動きを象徴しています。
