Jadawin 曰く、 "電机本舗が、バッファオーバランを根本的に解決するCPUアーキテクチャを提案し、特許出願中らしい。要するに一つのスタックに関数への引数と戻り番地を積むことが問題なのだから、それらを分ければ良いという発想。このアイデアの妥当性、特許として類例の有無など、/.諸兄の議論をお願いしたい。"
その前に、コンパイラで解決する方法があるぞ (スコア:4, 参考になる)
CPUアーキテクチャを変更する前に、コンパイラによって解決する方法がいくつか提案されている。ひとまず日本語で読めるものとしてこれを読んでみよう。
江藤 博明, 依田 邦和, propolice:スタックスマッシング攻撃検出手法の改良 [ipsj.or.jp], 情報処理学会論文誌, Vol.43 No.12, pp.4034-4041. (2002)
Re:その前に、コンパイラで解決する方法があるぞ (スコア:1)
いくらセキュアなCPUアーキテクチャを開発しても
数千万台現存するであろうx86ベースPCの脆弱性解消
には何の役にも立たないし.
・・・コンパイラレベルでセキュリティ問題を解決した
OSが登場するとWindows支配がひっくり返るのかどう
かはよくわからないが.
Forth (スコア:3, すばらしい洞察)
真っ先にForthが思い浮かびましたが。
たしかスタックが2本あって、片方がリターンスタックと言ったような……
Exec Shieldと個人的な疑問 (スコア:3, 参考になる)
http://people.redhat.com/mingo/exec-shield/
原理は、実行コード領域を、下位メモリの「0x00000000~0x0100FFFF」にすることで、アドレス4バイトのどこかに必ず、`00'が入るため、文字列の終端となり、それ以上の不正コードを文字列としてスタックに積むことが難しくなる、ということです。
“ASCII-armored Area”と呼ばれるそうですが、なんだかなぁ…
そもそも、データ領域とコード領域をCPUレベルで区別し、データ領域のインストラクションの実行を防ぐは難しいのでしょうか? また、他にCPUレベルでスタックオーバーフロー特有のセキュリティホールを防御する研究というのはないのでしょうか?
Re:Exec Shieldと個人的な疑問 (スコア:1, 興味深い)
Re:Exec Shieldと個人的な疑問 (スコア:3, 参考になる)
> Princeton/Harvard architectureの違いくらいは知ってるんでしょうね?
これだけだと何なんで, 参考になりそうなページ [yamanashi.ac.jp]を紹介しておきます. 多くのページではハーバードアーキテクチャをキャッシュ構成の話としてのみ扱っていますが, データとコードをバス上で分離するというアーキテクチャは特に組み込みCPUで多用されています. これによりコード部分はROM, データ部分はRAMに置くという経済的かつ安全な構成が簡単に実現できるわけです. 同様の機構は例えばMC68000の様な汎用CPUでも実装されていて, この場合プロセッサステータス信号でユーザモード/スーパバイザモード, コード/データの区分をつけられるようになっています.(普通のパソコンで使っている例はありませんが)
Re:Exec Shieldと個人的な疑問 (スコア:1)
ハーバードアーキティクチャと言えば、PICマイコン [microchip.co.jp]の命令のバス幅(14bit)とデータのバス幅(8bit)が一致していないのに感動した覚えがあります。
そりゃ、別物なんだから一致させる必要はないんですよね。
Re:Exec Shieldと個人的な疑問 (スコア:1, 参考になる)
(386以降なら64Kの壁もない)
だからスタックを書き換えてデータ領域にジャンプしても実行しないようには出来るはず。
だけどその能力をOSを使ってるかはまた別の話。
Re:Exec Shieldと個人的な疑問 (スコア:1, 興味深い)
CPUによっては (スコア:1, 参考になる)
あります。この場合、バッファーオーバーフロー攻撃でスタック
上に実行コードを置いてもアクセス違反で実行できません。
IA32ではセグメントにはリード権限と実行権限が独立に設定可能
なのですが、ページではリード・ライト権限しか設定できないの
でこの方法で防御するのは面倒です。
# それでも使ってる実装もLinuxのバリエーションであったはず
Re:Exec Shieldと個人的な疑問 (スコア:1)
ここだとセグメントを使った方法とページのフラグを使った方法が書いてある。セグメントはいわゆるコードセグメントとデータセグメントに分けて使う方式。フラグの方はスーパバイザフラグを流用して、non-exec のページに Supervisor フラグを立てておくと、アクセス時に fault が起きるのでそこでチェックする方式。詳細は上の URL からたどって読んでみてください。
Re:Exec Shieldと個人的な疑問 (スコア:1)
Re:Forth (スコア:3, 参考になる)
MC6809だとハードウェアスタックポインタ(S)レジスタとユーザスタックポインタ(U)レジスタという, そのものズバリなレジスタが用意されています. 通常のFORTH実装だとこれをそのまま使うことが多いのですが, OS-9で使う場合にはSレジスタはシステムコール用に使われているので, 他のXやYレジスタをスタックポインタに使う実装にすることが多かったです.
Re:Forth (スコア:1)
Re:Forth (スコア:1)
それって何て本ですか。こっそり教えて。
「慎重に実装することにより」とあるが (スコア:3, 興味深い)
たとえばCでいうところのsetjump()/longjump()みたいな、 関数の引数・返値が積まれるのと共通の スタック上にリターンアドレスがあることを前提にした 書き方がされることがあるプログラムは ユーザランドですら既にあるのをどう対処するか 困りそうじゃないですか。
8087エミュレータやOSの未定義命令トラップをはじめとする 例外ハンドラのように、 スタック上のリターンアドレスを間接アドレシングのために プログラムで明示的に拾って使うプログラムでは以下同様
結局、スタック上のリターンアドレスをデータとして叩く プログラムは結構あるので、 リターンアドレスの空間を分けちゃうとなると、 そちらを明示的に指定するインタフェース(=命令拡張)が 必要になるじゃない。 スタックに詰まれる物の数が変わるとオフセットだって変わるし。
あ! オフセットが変わるといえば、 関数呼び出し時って、返値をレジスタ渡ししない場合は
あと、IA32に限りませんが、 レジスタを増やすことはタスク構造体が膨らむことに 直結するわけで、OS自体のバイナリ互換性は損なわれますよね。
結局、根本的なところで、リターンアドレスを扱う命令は call/return命令だけで収まるはずがないので、 ぱっと思いつくだけでも これだけ問題山積みなような気がする。 どう「慎重に実装」すればこの辺を透過に扱えるんだか 実施例に記載して欲しいな。
Re:「慎重に実装することにより」とあるが (スコア:1, すばらしい洞察)
signal (ぼそ
# いやマジ、大変なんです
Re:「慎重に実装することにより」とあるが (スコア:1)
スタックオーバフローは実行時環境設計の不備 (スコア:2, 興味深い)
少なくとも、スタックをアドレスの下位から上位にとれば、文字列データが溢れても復帰番地を壊すことはありません。言語仕様からスタックをどの向きにとるかは、決められません。
あるいは、スタックをリンクトリストとして構成すれば、文字列データが溢れた場合の壊れる場所が一定にならない。IBMのOS360では、セーブエリア=復帰用スタックはポインタでつながれたリストで構成されていました。
以上、古代の計算機科学学習者の繰り言です。
# なぜ人はいまだにCを使うのでしょうか。
Re:スタックオーバフローは実行時環境設計の不備 (スコア:3, 参考になる)
呼び出し元関数のローカル変数として確保したバッファがあるとする。それへのポインタを引数に渡して関数呼び出しをすることはよくあるよね。呼び出された関数のコードが、その引数をバッファとしてアクセスするときに、境界チェックを怠るということもよくある。
この場合、スタックをアドレスの下位から上位にとると、呼び出された関数のフレームは、呼び出し元のバッファより上位に配置されるので、そのバッファが溢れれば、復帰番地が上書きされることになる。
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
そこに仕事があるから。
# 俺だって、俺だって他の言語でっ、、他のっ、、、
# クライアントや権力をがっちり握った老人が'80で停止してるんです。えぇ。
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
# 記憶はこのままで
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
確かにそうではあるが、でも同時に
「いつまでも○○だけで喰えると思ってる風潮を何とかしてほしい」
とも思う。○○は C でも C++ でも Java でも COBOL でも Pascal でも何でも。
// いや、実際そういう人いるし…。
This cookie has a scrap of paper inside. It reads:
If you can't learn to do it well, learn to enjoy.
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
>「いつまでも○○だけで喰えると思ってる風潮を何とかしてほしい」
これって同じことの裏表ですよ。
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
異議あり.
「プログラマが注意」できるという仮定がそもそも非現実的.
安全が問われるものはヒトが注意散漫でも問題を防げる仕組が必要.
#プログラミングに航空機や原発のようなフェイルセーフというのも大袈裟とは思うが
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1, 興味深い)
Re:スタックオーバフローは実行時環境設計の不備 (スコア:1)
この場合、OSプログラマとクラックプログラマの両方にとって
使える/使えないの条件が「だいたい同じ」なのでしょうね。
よーし、じゃあ私は (スコア:2, おもしろおかしい)
特許取るぞ!
Re:よーし、じゃあ私は (スコア:1, 参考になる)
実行権限はセグメント単位で指定できます。
毎回セグメント切り替えでは駄目なのでしょうか (スコア:2, 興味深い)
すべての関数呼び出しにおいて、保護モードを使うという
方法では駄目なのでしょうか。near callではなくて、
すべての関数呼び出しを、セグメントディスクリプタの
切り替えを伴うfar call(でよかったんでしたっけ)にして、
コード、データ、スタック等について細かくセグメント
わけして保護を行なうという。
オーバヘッドが猛烈にかかることは分かりますが。
#昔メインフレームでそんなことしてたので。
Re:毎回セグメント切り替えでは駄目なのでしょうか (スコア:2, おもしろおかしい)
足と同じセグメントに銃を置いてはいけない。
リプレースの経済性 (スコア:2, すばらしい洞察)
今回の方法だと、実際のセキュアなシステムにするための作業は、(1)ハードウエア取り換え、(2)ライブラリ取り換え、(3)場合によったらコンパイラなどのツール取り換え、etc..などが必要になりますが、ソフトウエアだけであれば、(1)の作業がなくなるので、単純に言って、経済性がよりすぐれたものになるかと思います。
せっかくハードを取り換えるのでしたら、ハードの取り換え「だけ」で済むようなものでないとうけいれられにくいのではないかな?
Re:リプレースの経済性 (スコア:1)
Re:リプレースの経済性 (スコア:1)
たとえば、コンパイラを変えたらコンパイラ自体の動作検証に加え、ソフトウェアを全部再コンパイルして各ソフトウェアの動作検証をしなければならなくなる(動かなくなるソフトの対応も含む)ので、全部ソフトでやる方が常にコストが安いとは言えないと考えています。ありがちですが適用領域を見て選ばなければならないと思います。
もちろん、ハードやソフトの色々な対応が選択肢として提供されていることはとても重要なことなので、ソフトだけで OK とかハードだけで OK とかの風潮になるのは怖いですね。
100%互換って可能? (スコア:2, 参考になる)
「慎重に実装することにより、従来のIA32に対して100%互換性を維持できる。過去のソフトウェア資産を損なうことなくセキュリティを向上できる。」
って可能だろうか?「慎重」なところが特許か?
私見では、レジスタ増やしたらsetjmp/longjmp, thread, signal, kernelその他、context switchするところの変更や再コンパイルは避けられないと思う。
で、再コンパイルするなら、適当なレジスタをデータスタックとして使うコードを吐くようなコンパイラを作ればいい話で、CPU変更の必要は無くなる。
context switchを使ってないか、共有ライブラリ等で差し替え可能かつバイナリに埋め込まれたcontext保存領域(例えばjmp_buf)のサイズが変わらないのなら、userlandのバイナリ実行ファイルの互換性は保たれるかもしれない。
とりあえず、いきなりCPU変更とか言い出す前にエミュレータかなにかで実用性を検証してほしいところだ。
スタックと言っても (スコア:1, 参考になる)
インデックスレジスタで代用できるように思えるのだけど. 現に多くの RISC 系 CPU では,CPU アーキテクチャのレベルではスタックと言う概念は無くて,コンパイラ側の方で汎用レジスタのどれか1つを「こいつはスタックポインタとして使うぞ」と勝手に決めて使っているだけだし.
というわけで,コンパイラ(と OS)の実装レベルで,例えば EAX ~ EDX のどれかを「データ用のスタックポインタ」として使うことにしてしまえば,CPU コアの変更はいらんと思うんだけど,どうなんでしょ. x86 では命令セットの関係で,こういうのは難しいのかなぁ.
# まぁ,ただでさえ少ない汎用レジスタを更に減らす,というのもちと悲しい気もするが.
Re:スタックと言っても (スコア:1)
Re:スタックと言っても (スコア:2, 参考になる)
現存のCISC CPUの多くは、「スタックポインタ」と名付けられた レジスタを持ち、また暗黙のうちにスタックポインタを インクリメント/デクリメントするJSRとかRETとかの命令を持っている。
一方RISCは、汎用レジスタのどれかをスタックポインタとして使うことがおおい。
と言いたかったのでは。#409307 は。 もちろん、専用のスタックポインタを設けず汎用レジスタを スタックポインタに充てるのはRISCの専売特許ではない。 PDP-11とか、昔のCISCにもあった。
Re:スタックと言っても (スコア:1, 参考になる)
一方、言語系からは、スタックポインタ用に統一したレジスタの使い方が互換性や外部プログラムの再利用のために必要(ほぼ必須と言ってもいい)なので、CPUが「スタックポインタレジスタ」というのを用意してくれれば(あるいはMIPSのように「汎用レジスタ29番はスタックポインタ$spとして使う」、というしきたりを設定してくれれば)便利 なことこの上ない、というわけです。
だから「RISCならスタックポインタレジスタはどうこう」というのはまったく勘違いもいいところで、重要なのは、現在の言語系ではせいぜいアクティベーションレコードかディスプレイくらいしか実用的な手続き呼出し機構の選択肢がなく、そのどちらもスタックを必要とするという事実なのであって、それはCPUのアーキテクチャとは無関係なのです。
CPUメーカー (スコア:1)
まぁ、10年先のことはわからないので、なんともいえないですけどね
Re:モトローラ6809 (スコア:1)
OS-9/6809ではAPIへのパラメータって、全部Uレジスタ経由でしたっけ?またOS-9/6809用コンパイラの吐き出すコードも、リターンアドレス用、関数への引数用というように用途を分けて使ってましたっけ?ああ、もう全然覚えてないや。^_^;もちろん #409397が間違っているっていっているんじゃなくて、単なる質問です。
私の印象では、Uレジスタってどっちかというと単なるインデックスレジスタとして使われることが多かったような気がします。また関数のCall/Returnの度に2つスタックをいじるより、1つだけにしたほうが簡単でコードサイズ面でも有利そうだし、レジスタを1本開けられるので、私だったらそうコンパイラを実装しそうです。
vyama 「バグ取れワンワン」
Re:モトローラ6809 (スコア:1)
S/Uあるし、X/Yあるし。
#初めて(それと意識して)接したCPUだったので感慨深いG7
#はじめてアセンブラのニモニック見た(BASICしか知らなかった)ときは別世界すぎてビビった。
Re:モトローラ6809 (スコア:2, 興味深い)
それは困った。:-)
6809の場合、UとSをどう使うかはプログラマの自由だったのは確かだけどちゃんと私はUはスタックで使っていましたよ。ポインタはXとYがあってそれぞれ,x++とか,--yとかできたから、アセンブラをしばし経験したあとでCに触れた時は何だコリャ、まるでアセンブラを同じではないかと思いましたし。
#アセンブラが欲しくてFLEX9を買った前科があるからなぁ。。。
x++,--y(オフトピック) (スコア:1)
関係ないけど、私もvirtualさんを困らせちゃう一人だ。^_^;
vyama 「バグ取れワンワン」
Re:x++,--y(オフトピック) (スコア:1)
ちょっと意図がつかめないんですが、C言語でポインタに対して++xと書くと、マシン語レベルだと、x += sizeof(xがポイントする構造体/データ)となるってことを言ってます?このことだったら、私もこれは便利だし、理に適っていると思いました。
ついでに言えば、char *でポインタをキャストすれば、手持ちの環境ではインデックスレジスタをいじっているのと変わらないってのもアセンブリ言語から入ったから身としては、とっつきやすかった。(笑)
vyama 「バグ取れワンワン」
Re:モトローラ6809 (スコア:1)
Re:モトローラ6809 (スコア:1)
それでもスーパーセカンドソース(?)のHD63C09とかにはTAS命令に使える隠しコマンドがあったような気が・・・
いやあ、8bitとは思えないなかなか楽しいCPUでした。
Texas Instruments TI32032 (スコア:1)
もうCPU作らなくなったよね、TI。(悲)
-- crazy_beat