2011-07-14 12 views
1

POSIXはと言っています。 "システムは常に、オブジェクトの最後の部分ページをゼロで埋めます。 "であり、LinuxとFreeBSDの両方のドキュメントには、マニュアルページに似た言葉があります。
これは、(マップされた範囲外の)最後の末尾のバイトを厳密に読み取るわけではありませんが、まだ明確に定義されているため、がクラッシュすることはありません。その領域への書き込みでさえ、よく定義されています。最後にマップされたページ

一方、Windowsのドキュメントでは、ブロックサイズよりも小さい範囲の末尾のバイトについては何も言われておらず、ファイルよりも大きなマッピングを作成するとファイルサイズが増加し、は必ずしもデータ。
これは間違った情報か歴史的なものかと思います(Win95に戻ってきたのかもしれません)。 SetFileValidDataには、以前に削除されたファイルのデータが表示される可能性があるというセキュリティ上の懸念があるため、非標準のユーザー権限が必要です。 Windowsカーネルの開発者がランダムファイルをマッピングすることによって誰かが些細なことにこれを回避することを許可した場合、それらはかなりばかげていなければなりません。
私のWindows XPでの観察では、新しいページがゼロプールから引き出されているように見えます。空のページの書き戻しの場合は、ファイルが暗黙的にスパースされているか、書き戻しが非常に賢明な方法で行われます何時でも、ギガバイトの範囲であっても)。

だから質問は何ですか?

変更されたファイルのサブセットを検出するために、(おそらく何千もの)ファイルのハッシュ値を計算する必要があります。実際のアルゴリズムは実際問題ではありませんが、SHA-256をアルゴリズムと見なすことができます。
それはもちろん大きな問題ではありませんが、すべてのソフトウェアのように、時間がかかりませんし、メモリも使用しないでください。

このようなハッシュを計算する通常の方法は、メッセージがハッシュ関数のブロックサイズ(たとえば64バイト)に応じたサイズでゼロかどうかをチェックすることです最後に不完全なブロックを埋め込みます。さらに、ハッシュはアラインメントの要件を有する可能性がある。
これは通常、メッセージの完全コピーを作成するか、最後のブロックの0パッド付きコピーを加えた1つのブロック以外のすべてをハッシュする特別なコードを書き込む必要があることを意味します。または類似のもの。ハッシュアルゴリズムは、しばしばそれ自身のためにそのようなことを静かに行います。いずれにしても、それは多くのデータを移動し、より複雑なものを望むでしょう。

ここで、メモリマップファイルを直接ハッシングするという誘惑があり、ファイルマッピングが必然的にメモリページに依存するという事実に頼っています。したがって、開始アドレスと物理的にマップされた長さの両方が、4kBの倍数(あるシステムでは64kB)であることが保証されます。もちろん、それらは自動的に64,128、またはハッシュが持つ他のブロックサイズの倍数でもあります。
セキュリティ上の理由から、実際には、古いデータを含むページを提供するOSはありません。

これは、整列、パディングなど何も気にせずにファイル全体を丁寧にハッシュできることを意味し、データのコピーを避けることができます。 は、マップされた範囲の最後を過ぎて数バイトを読み取ることができますが、同じページ内にある必要があります。

もちろん、は技術的にはです。マップされた範囲外の最後のバイトを読み取ることは、とにかく、malloc(5)が常に8バイトのブロックを返すというよりも、余分な3バイトを使用しても安全です。

明らかなことを除いて、これは「ちょうどうまくいく」という私の前提ですが、大きなプラットフォームでは見逃してしまう重大な問題がありますか?

理論的にも歴史的なオペレーティングシステムにもあまり興味がありませんが、と少しでものままにしておきたいと思います。つまり、デスクトップコンピュータや「典型的なホスティングサーバー」(Windows、Linux、BSD、OSXなど)で遭遇する可能性のあるものに対して確実に動作するようにしたいと考えています。
1985年のオペレーティングシステムが存在し、最後のページを読み込み不可とマークし、フォールトハンドラ内に厳密なバイト範囲を強制する場合、私はそれで大丈夫です。あなたは皆を幸せにすることはできません。

答えて

1

このようなハッシュを計算する通常の方法は、メッセージがハッシュ関数のブロックサイズ(たとえば64バイト)に応じたサイズかどうかをチェックし、最後の不完全ブロックがゼロでない場合はゼロで埋めます場合。

実際はありません。この方法では、最後のブロックの長さを見つけることができませんでした(ゼロがあったか、パディングから来たか)。パディングは少し違っています:1つのスキーマでは、ブロックの最後まで常に1つの1を追加し、次に0を追加します。

データがブロック境界で終了する場合は、別のブロックが必要であることを意味します。この余分なブロックは、余分なページに含まれる可能性があります。だから私はあなたが説明したように動作するとは思わない。

マップされた範囲の最後を数バイト越えて読み取ることがありますが、それは同じページ内にある必要があります。

これはIntel/AMD上で動作するはずです。他の人には何もできないと思います。 i386 + CPUにはセグメントとページがあります。セグメントはバイト境界で終了することができますが、AFAIKでは現在のOSで使用されていません。あなたがあなたのページにいれば、それはあなたのものです。

だから私はそれがこのように仕事ができると思う:

  • 非常に最後のブロックがフルサイズをしていない場合には、それ以外の場所
  • でパディングを行い、準備された定数に最後のラウンドを実行しますブロックのような1000000000000000
+0

1つの1の後にゼロの埋め込みを追加すると、0で埋められるよりも利点がありません。これは偶然にも特定のハッシュの規則ですが、それだけです。 1が不正な文字でない限り、長さを決定することはできません。いずれの場合も、長さは別々に​​保存する必要があります。私のページにあるものはすべて私のものであるという前提が(Qに述べられているように)起こる可能性はありますが、必ずしも真実ではありません。これが実際の質問についてです。つまり、少なくとも3バージョンのWindowsでは確実に動作することを確認できます(とにかにPOSIXによって保証されています)。 – Damon

+0

長さの決定には役立ちませんが、それを「決定」する必要はありません。あなたは攻撃を防ぐ必要があります。このため、ハッシュによっては、パディングが十分でない場合があります(例:CubeHashの場合)。しかし、私のポイントは、ブロックの最後の穴だけではなく、より多くのスペースが必要だということでした。 – maaartinus

+0

OSがセグメントレジスタを使用しない限り、ページ境界を越える前に干渉するような変更はありません。 AFAIK、現代のOSはセグメントレジスタを使用していませんが、それはあなたが簡単に確認できるものです。 – maaartinus

関連する問題