Xxhash: ストリーミングXXH3シード+ copyStateで無料で使用

作成日 2020年05月19日  ·  7コメント  ·  ソース: Cyan4973/xxHash

@koraaのクレジット。

現在、このコードは無料発行後に使用されます。

void bugged(void)
{
    XXH3_state_t *a = XXH3_createState();
    XXH3_state_t *b = XXH3_createState();
    XXH3_64bits_reset_withSeed(a, 0x1234567890abcdefull);
    XXH3_copyState(b, a);
    XXH3_freeState(a);
    // Bug
    XXH3_64bits_update(b, "BUGGED", strlen("BUGGED"));
    XXH3_freeState(b);
}

これは、 a->secreta->customSecret a->secret指しているためであり、 XXH3_copyStateはそのポインタを更新しないため(文字通りmemcpy )、 b->secreta->customSecret b->secret指します。

aが解放された後、 b->secretは無効なポインタになります。

xxh3 use after free

最も参考になるコメント

最良のオプションはNULLポインタだと思います。

XXH3_updateの先頭にはすでに5つのブランチがあります。 もう1つ実行しても問題はありません(特に、バッファーがいっぱいになったときにのみ必要になるため)

全てのコメント7件

#361の説明を参照してください。

いくつかのオプションがあります。

動作に変更がない最初の最も単純なオプションは次のとおりです。

XXH_PUBLIC_API XXH_errorcode
XXH3_copyState(XXH3_state_t* dst, const XXH3_state_t* src)
{
    XXH_memcpy(dst, src, sizeof(XXH3_state_t));
    if (src->secret == &src->customSecret[0]) {
        dst->secret = &dst->customSecret[0];
    }
    return XXH_OK;
}

しかし、これは少しハッキーです。

2番目のオプションは、予約済みフィールドの1つを使用して、それがどの種類の状態であるかを示し、生のポインターを比較する代わりにそれを使用することです。

これを実行しているときに、エラーチェックを追加して、64ビットと128ビットの状態が混在しないようにすることができます。 これにより動作が変わりますが、その使用法は意図されたものではなく、とにかくUBと見なすことができます。

3番目のオプションは、シードモードにNULLポインターを使用することです。これがNULLの場合、 customSecret代わりにsecret customSecret使用しますが、これによりブランチが追加されます。 ただし、状態管理からのオーバーヘッドはすでに十分にあるため、目立たない違いが生じる可能性があります。

最後のオプションは、シークレットポインタのコピーをmalloc()することです。

これにより、ABIが変更されます。これは、スタックメモリ上で完全に実行することができなくなったためです。 また、 kSecret場合は非常に冗長になります。

ただし、 reset_withSeed()後でカスタムシークレットを無効にすることができ、状態のサイズを縮小することができます。

おっと、誤って間違ったボタンを押しました:facepalm:

4番目のオプションがあると思います。常にエントロピープールを構造にコピーします。 ただし、これにより、プールはデフォルトのシークレットのサイズになります。 それはちょっといいかもしれませんが、オフラインエントロピープール生成の最適化の基礎を形成する可能性があります。

uint64_t XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t data, size_t size);

実装は、指定されたデータでXXH3状態を「拡張」します。 状態を変更せずにすぐにハッシュを返します…

編集これは可動性を維持します。 どのIMOは使いやすさにとって大きな恩恵であり、錆の統合に高く評価されます。

uint64_t XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t data, size_t size);
error: expected ')'
...XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t data,...
                                            ^
note: to match this '('
uint64_t XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t...
                                    ^
1 error generated.

これは何ですか? あなたがそこで何をしようとしているのかわかりません…:smirk:

可動性は素晴らしい機能であり、固定サイズの秘密で簡単になります。

実際には、固定サイズのシークレットを使用するとすべてが簡単(かつ高速)になりますが、APIを台無しにしたくありません。

最良のオプションはNULLポインタだと思います。

XXH3_updateの先頭にはすでに5つのブランチがあります。 もう1つ実行しても問題はありません(特に、バッファーがいっぱいになったときにのみ必要になるため)

x86_64とi686は、分岐せずにこれを実行できることにも注意してください。

        lea     tmp, [state + offsetof (state::customSecret)]
        test    secret, secret
        cmove   secret, tmp

これもARMではブランチレスです

        cmp     secret, #0
        it      eq
        addeq   secret, state, offsetof(state::customSecret)

およびAArch64の場合:

        add     tmp, state, offsetof(state::customSecret)
        cmp     secret, #0
        csel    secret, tmp, secret, eq
このページは役に立ちましたか?
0 / 5 - 0 評価