最も高価なシングルバイトエラー

Poul-Henning KampによるQueue電子ジャーナルの最近の投稿の翻訳に注目してください。



NUL完全なテキスト文字列を使用することを選択した場合、Ken、Dennis、およびBrianは間違っていましたか?



ITは、現代の西洋経済を刺激し、実行します。 したがって、ITエラーに関連する莫大な金額についての見出しをよく目にします。 ITまたはCI [コンピューターサイエンス]で最も高価なソリューションは何ですか?



最近、十分な専門家が、PlayStation Networkに関連する問題からSonyに金銭的な影響を与えることについて言及しましたが、そのようなイベントはこの文脈では重要ではありません。 学校にいたとき、ギネス記録の検査官と話をする機会がありました。彼は、何かが偶然に実際の記録になるだけではなく、人間の意図から始まる因果関係があるはずだと説明しました(たとえば、26人の高校生をVolkswagen Beetleが音楽の先生で、ドアを閉めました。



ソニーは(おそらく)セキュリティにほとんど注意を払わない場合にどのような混乱が起こるかを考えたくないので、このような貯蓄の例は他には当てはまりません。 別の候補者は、Gary Kildallではなく、IBMがBill Gatesをパーソナルコンピューターのオペレーティングシステムプロバイダーとして選択することです。 この決定による損害は依然として猛烈なスピードで蓄積しています。Stuxnet[約。 あたり ネットワークワーム]とOOXML ISO標準化プロセスのゆがみは、被害がどれほど広範囲に広がるかを示しています。 しかし、これはITまたはIPに関連する決定ではありませんでした。 現在知られているように、これは、KildalがIBMの非開示要件を受け入れることを拒否したことに基づくビジネス上の決定でした。



より適切な例は、MS-DOS用の独自のディレクトリ/ファイル名区切り文字を発明することを決定することです。Unixで使用されたスラッシュ(/)またはオペレーティングシステムでDECを使用したドットではなく、バックスラッシュ(\)が選択されました。 実際の被害は比較的中程度ですが、この解決策も良い例としては当てはまりません。実際の解決策ではなかったため、真の優先事項でした。 IBMはUnixを無視してコマンドフラグにスラッシュを使用することを選択し、ピリオドはファイル名と拡張子の区切り文字として使用されたため、DECの例に従うことはできませんでした。



宇宙探査の歴史は、促進された高価な過失の全セットを提供しますが、興味深いことに、私は単一の適切な候補を見つけることができませんでした。 Fortran構文エラーとシャトルトリップコンピューターの同期エラーは、意図がないため適切ではありません。 プロジェクトの一部を帝国単位で維持し、他の部分をメートル単位で維持することは「ランダムな管理行為」であり、SCまたはITには適用されません。



私が見つけることができる最良の例は、C / Unix / PosixでNUL完全なテキスト文字列を使用することです。 非常に簡単な選択がありました。Cは、文字列をアドレス+長さのタプルとして、または単にアドレスと何らかの文字(NUL)で文字列の終わりを示すものとして表現する必要がありますか? ダイナミックなトリオ、ケン・トンプソン、デニス・リッチー、ブライアン・カーニガンが70年代前半に行ったのはこの決定であり、彼らはどんな方法も自由に選択できました。 決定の単一の記録を見つけることができませんでしたが、それは弱い候補として認識しています。この決定が意識的であったという証拠はありません。



それにもかかわらず、研究から判断できる限り、当時のほとんどのプログラミング言語ではアドレス+長さの形式が好まれましたが、アドレス+マジックマーカーは主にアセンブラーで書かれたプログラムで使用されていました。 C言語は、よりポータブルで高レベルの言語としてアセンブラーから発展したため、ケン、デニス、ブライアンがそれについて考えさえしなかったと信じるのは困難です。



アドレス+長さ形式を使用すると、アドレス+マジックトークンと比較して1オーバーヘッドバイトのコストがかかり、PDPコンピューターのメインメモリが制限されていました。 言い換えれば、この例は、私たちが毎日行う多くの同様の決定のように、ITまたはIPに関連する理想的で典型的かつ合理的な決定になる可能性があります。 しかし、非典型的な経済的結果をもたらすのはこの決定です。



ハードウェア開発コスト





当初、Unixはハードウェアと一連のコマンドの開発にほとんど影響を与えませんでした。 あたり プロセッサ]。 Z-80やDEC VAXなど、文字列を操作するための命令を提供したプロセッサは、はるかに一般的なアドレス+オフセットモデルを使用してこれを行いました。 UnixとCがサポートされると、NUL完全文字列が最適化の目標になりました。 CPU開発者は、それらを操作するための指示を追加し始めました。 例としては、1992年にIBMによってES / 9000 520に基づくプロセッサーに追加された論理文字列アシスト命令があります。



CPUに命令を追加することは安価ではなく、具体的で定量化可能な金銭的理由がある場合にのみ発生します。



パフォーマンスコスト





IBMは、顧客がそのような文字列を処理するために高価なCPUサイクルを費やしたため、NUL完全文字列を操作するための指示を追加しました。 ただし、これは、アドレス+長さの形式を使用した場合に必要なCPUサイクルが少なくなるという意味ではありません。



仮想メモリシステムについて考える場合、質問は省略されます。 既知の長さのバイト文字列の移動を最適化すると、ソースラインまたは宛先ラインの一部ではないメモリ領域に影響を与えることなく、メモリバスとキャッシュラインの全幅を活用できます。



1つの例は、FreeBSDのlibcライブラリです。bcopy(3)/ memcpy(3)実装は、可能な限り多くの情報を「符号なし整数」のフラグメントに移動します。通常は32または64ビットで、次にバイトコピーを使用して「後続バイトをクリア」します。コメントに記載されています。



NULで終了する文字列を使用する場合、1バイトを超える部分で作業しようとすると、NUL文字の後の文字にアクセスする可能性があります。 NUL文字が仮想メモリページの最後のバイトであり、次のページが定義されていない場合、「page not found」[「page not present」]エラーでプロセスがクラッシュする可能性があります。



もちろん、最適化されたコードを実行する前に、潜在的な落とし穴を特定するコードを作成できますが、これにより、すべての行移動操作に比較的高い固定コストが追加されます。



文字列の長さが事前にわかっている場合、すべてが異なります。



コンパイラ開発コスト





多くの場合、コンパイラは文字列について1つのことを知っています-特に文字列が一定の場合、その長さ。 これにより、プログラマーがソースコードでstrcpy(3)を使用した場合でも、コンパイラはより高速なmemcpy(3)を呼び出すことができます。



コードをさらに詳しく調べると、コンパイラーはより高度な最適化を実行できます。一部は非常に熟練していますが、これは誰かがコンパイラーでこれを実装した場合のみです。 最適化コンパイラの開発は決して簡単でも安価でもありませんでしたが、アップルがオプティマイザが大量にあるLLVM(低レベル仮想マシン)を使用してこれが変わることを期待していることは明らかです。



コンパイラによって実行される詳細な最適化の裏側は、ソースコードの全体的なレビューを行い、大量に並べ替える最適化です。 ソースコードが必要なものを正確に記述していることをプログラマが注意深く監視する必要があります。 Convex C3800シリーズスーパーコンピューターコンパイラーで作業したプログラマーは、「コンパイラーがあなたの元妻であるかのようにプログラムする必要がある」と説明しました。



安全費





コンパイラに敵意がない場合でも、ソースコードは攻撃に耐えられるように作成する必要があり、この点でNULが完成した行には悲観的な関係書類があります。 セキュリティの観点から見ると、完全な災害は(3)であり、これは「バッファが十分に大きくなると考えている」ことであり、この問題は「比較的制御可能」です。



ただし、制御を取得するということは、gets(3)がどこかで呼び出された場合にコンパイラがさらに文句を言うことを意味します。 15年の注目にもかかわらず、オーバーフローとアンダーランニングの文字列バッファは攻撃者にとって好ましい攻撃ベクトルであり、あまりにも頻繁に利益をもたらします。



これらのリスクはすべてのレベルで削減されています。 CPUのメモリ管理ハードウェアに、実行を禁止する長い欠落ビットが追加されました。 オペレーティングシステムとコンパイラは、多くの場合パフォーマンスのために、アドレス空間のランダム化を追加しました。 静的および動的なプログラム分析は、陰湿な診断が間違いまたは巧妙なプログラミングであるかどうかを調べるために数え切れないほどの時間を費やしました。



それにもかかわらず、ソニーの問題がバッファオーバーフローまたは行末の誤った解釈で始まったことが判明したとしても、誰も驚かなかったでしょう。



スラッシュドット感覚の防止





私たちは間違いから学び、この記事の「黄色」の見出しを思い付きません。 ケン、デニス、およびブライアンは、30年前に行われた選択の結果をすべて予見できなかったため、何も保証しませんでした。 私の知る限り、この微妙な解決策が悪い考えであることを理解するのに15年かかりました。 おそらく私の決定はどれも長く続きませんでした。



言い換えれば、ケン、デニス、ブライアンはすべてを正しくやった。



しかし、これは問題を解決しません





多くの人々にとって、Cは死に、$ {lang}の絶え間なく変化する短期的な価値のために、$ {lang}は未来の言語です。 実際には、他のすべての言語は、Posix APIおよびNUL完全なCの文字列の上に直接または間接的に配置されます。



Java、Python、Ruby、またはHaskellプログラムがファイルを開くと、ランタイムはファイル名をNUL終了文字列として渡し、開きます(3)。 または、queue.acm.orgをIPアドレスに変換するときに、ホスト名をNULで終了する文字列としてgetaddrinfo(3)に渡します。 これを続ける限り、PDP / 11でプログラムを実行する場合のすべての利点と、他のプログラムで実行する場合のすべての欠点を保持します。



ここでは、想像上の敵と戦うためのAPIの提案を書いて、機能、操作、エラー処理戦略を設定する方法を提供できますが、素晴らしい夜の完全な無駄になると確信しています。 PDP / 11と書かれたプログラムの有限数との後方互換性は、将来より多くのプログラムをより効率的かつ安全に書く可能性よりもはるかに重要であるため、経験はそのような提案がどこにも行かないことを示しています。



したがって、ケン、デニス、およびブライアンの決定のコストは、何世紀にもわたって古代ローマをほとんど埋め尽くしていたため、蓄積し続けます。



参照資料



1.コンピュータービジネスレビュー。 1992.トップエンドES / 9000sのパーティショニングとEsconの機能強化。 http://www.cbronline.com/news/ibm_announcements_71

2. ViewVC。 2007. /head/lib/libc/string/bcopy.cの内容。 http://svnweb.freebsd.org/base/head/lib/libc/string/bcopy.c?view=markup

3.ウィキペディア。 2011.救命ボートのスケッチ。 http://en.wikipedia.org/wiki/Lifeboat_sketch



All Articles