1

Programming in Rust (PDF)の例:

#[derive(Debug)]
enum IntOrString {
    I(isize),
    S(String),
}

fn corrupt_enum() {
    let mut s = IntOrString::S(String::new());
    match s {
        IntOrString::I(_) => (),
        IntOrString::S(ref p) => {
            s = IntOrString::I(0xdeadbeef);
            // Now p is a &String, pointing at memory
            // that is an int of our choosing!
        }
    }
}

corrupt_enum();

コンパイラはこれを許可しません:

error[E0506]: cannot assign to `s` because it is borrowed
  --> src/main.rs:13:17
   |
12 |             IntOrString::S(ref p) => {
   |                            ----- borrow of `s` occurs here
13 |                 s = IntOrString::I(0xdeadbeef);
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `s` occurs here

しかし、それがあったとしましょう。それはどうですか

pは、&String選択した int であるメモリを指している です!

悪いことですか?

4

1 に答える 1

4

関連する型のメモリ レイアウトを作成してみましょう。IntOrStringどのバリアント ( 0= 数値、1= 文字列) であるかを判別するための 1 バイトがあり、その後に数値または一連の UTF-8 文字の先頭へのアドレスのいずれかである 4 バイトが続きます。

s0x100 でメモリに割り当てましょう。バリアントは 0x100 にあり、値は 0x101、0x102、0x103、0x104 にあります。さらに、値の内容がポインタであるとしましょう0xABCD。これは、文字列のバイトが存在する場所です。

マッチ アームIntOrString::S(ref p)が使用さpれると、値が設定されます0x101。これは値への参照であり、値は 0x101 から始まります。を使用しようとするpと、プロセッサはアドレスに移動し0x101、値 (アドレス) を読み取り、そのアドレスからデータを読み取ります。

このs時点でコンパイラが変更を許可した場合、新しいデータの新しいバイトが に格納されている値を置き換えます0x101。この例では、値に格納されている「アドレス」は、任意の場所 ( 0xDEADBEEF) を指します。「文字列」を使用しようとすると、UTF-8 データに対応する可能性が非常に低いメモリのバイトを読み取り始めます。

これは学術的なものではありません。まさにこの種の問題は、整形式の C プログラムで発生する可能性があります。良い場合、プログラムはクラッシュします。悪いケースでは、想定されていないプログラムでデータを読み取ることができます。シェルコードを挿入して、攻撃者がプログラム内で記述したコードを実行できるようにすることさえ可能です


上記のメモリ レイアウトは非常に単純化されており、actualStringはより大きく複雑であることに注意してください。

于 2016-03-25T19:15:55.613 に答える