HN 日本語サマリー

← 一覧へ戻る
プログラミング

Chromium 148以降、Math.tanhはOSを紐付けるフィンガープリンティングが可能に

Since Chronium 148, Math.tanh is now fingerprintable to link underlying OS (scrapfly.dev)

341 pointsby joahnn_s163 コメント

要約

ブラウザのMath.tanh関数の実装がOS依存となり、OSごとに異なるビット列を返すことが判明しました。これはChromium 148以降で、V8が内部実装からプラットフォームのstd::tanhに切り替わったためです。この違いを利用して、ユーザーのOSを特定するフィンガープリンティングが可能になります。

全文翻訳

← 全ての投稿に戻る フィンガープリンティングは通常、canvas、WebGL、フォント、オーディオに関するものです。しかし、より静かな信号があり、それは数値の最後のビットに存在します。 任意のコンソールでこれを実行してください: Math.tanh(0.8) // 0.6640367702678491 本物のLinux Chrome (glibc) // 0.6640367702678489 本物のmacOS Chrome (libsystem_m) // 0.6640367702678489 本物のWindows Chrome (UCRT) これは定数ではありません。近似値であり、正確なビットはそれを計算したOSに依存します。本物のMacは、Appleの数学ライブラリを通じてMath.tanhを実行します。Linuxはglibc1を通じて実行します。これら二つは、約4分の1の入力で意見が異なり、通常は最後の桁で1単位(1 ULP2)だけ異なります。Windowsは、Universal C Runtimeを通じて、数パーセントでこれら両方と意見が異なり、上記の入力ではすべて異なるビットに着地します。 同じ呼び出しを、3台の本物のマシンで本物のChrome 150で実行した場合: 呼び出し Linux (glibc) macOS (libsystem_m) Windows (UCRT) 分割 Math.tanh(0.5) 0.46211715726000974 0.46211715726000974 0.46211715726000974 すべて三者が合意 Math.tanh(0.7) 0.6043677771171636 0.6043677771171635 0.6043677771171635 Linuxのみ、1 ULP Math.tanh(0.8) 0.6640367702678491 0.664036770267849 0.6640367702678489 すべて三者が異なる、2 ULPの広がり Math.tanh(0.9) 0.7162978701990245 0.7162978701990245 0.7162978701990244 Windowsのみ、1 ULP DevToolsプロトコル上でChrome 150で測定: Linux (glibc)、macOS 26 on Apple Silicon (libsystem_m)、Windows 11 (ucrtbase.dll)。 tanh(0.5)は、全員が合意する約4分の3の入力のうちの1つであり、まさに無用なプローブとなっている理由です。 tanh(0.8)は、3つすべてを一度に分離するものの1つです。 適切な入力に対する1回のtanh呼び出しは、OSごとの署名です。 macOSを主張し、Linuxの数学ビットを返すと、あなたはあなた自身のUser-Agentと矛盾することになります。 この情報は新しいものです。Chrome 148まで、V8はバンドルされたfdlibm3ポートでtanh自体を計算していたため、すべてのOSで同じビットを返し、何も漏洩しませんでした。V8のコミットc1486295ae5はそれをstd::tanhに置き換え、ホストlibmを読み取ります。これはV8 14.8.57で最初にリリースされ、Chrome 148に相当します。Chrome 147以前はここで漏洩しません。Chrome 148、149、150は漏洩します。 Scrapflyは、数百の信号にわたって実際のブラウザと一致する必要があるブラウザを提供しています。数学は、その中でも難しいものの1つです。その理由と、それをどのように修正したかを説明します。 なぜ1つの関数が異なるビットを返すのか IEEE 7544は、doubleがどのように格納されるかを定義しています。sin、cos、tanh、expが正しく丸められることを要求していません。正しく丸めるのは高価なので、すべてのベンダーは速度のためにULPの断片を犠牲にするlibm5を配布しており、独自のminimax6係数、ルックアップテーブル、および削減定数を使用しています。 3つの実装、3つのビットセット: Linux: glibcmacOS: Apple libsystem_mWindows: UCRT7 (ucrtbase.dll) これらはほとんどの場所で一致し、分類するのに十分な頻度で分割されます。検出器は数学を必要としません。テーブルが必要です: 本物のmacOS Chromeはcos(1)に対してこのパターンを返し、本物のLinux Chromeはあのパターンを返します。1つのプローブ、1つの比較。 4つの落とし穴 「Macの関数を再実装する」というのは、接触すると壊れます。4つの理由。 1. 一部の数学のみが漏洩します。V88は独自の数学を配布し、静的にリンクしています: Math.exp、Math.pow、Math.atan、およびその他のほとんどは、バンドルされたllvm-libc9から、Math.sin / Math.cosはバンドルされたglibc由来のdbl-64ルーチンから来ています。これらはすべてOS上で同一なので、それらを偽装すると不整合が生じます。例外はMath.tanhです: Chrome 148以降、V8は以前使用していたバンドルされたルーチンではなく、プラットフォームのstd::tanhで計算するため、ホストlibmを読み取るようになりました。OSを漏洩する唯一のMath.*であり、その非対称性自体がチェック可能です。 2. JavaScriptの数学とCSSの数学は異なるコードパスです。CSSのsin()、cos()、atan2()はMath.sinとはコードを共有しません。レイアウトエンジンは角度を度単位で削減し、削減された値に対してプラットフォームのstd::sinを呼び出します。これは直接のラジアンsin()とは異なる結果をもたらし、ホストlibmにヒットするため、すべての7つのCSS三角関数が漏洩します。度削減とラジアンから度へのステップをビット単位で再現しました。単なるリーフ関数ではありません。 3. macOSには2つの数学ライブラリがあり、それらは一致しません。Apple Siliconは、スカラーlibsystem_mとAccelerateフレームワーク10のベクトルルーチン(vvsin、vvtanh)を搭載しています。これらは異なるコードです。100万回の入力で、関数によって10%から89%で分岐します。cos(0)を取ると、スカラーは正確に1.0を返し、Accelerateは0.9999999999999999を返します。したがって、「Appleの数学を再現する」ことは、ブラウザがどのライブラリをどのサイトで呼び出すかを知るまで未定義です。デバッグプロトコル上で本物のMacで本物のChromeを駆動し、正確なdoubleを読み取ることで解決しました。回答: スカラーlibsystem_mは、Math.tanh、CSS三角関数、およびオーディオコンプレッサーのサンプルごとの超越関数をバックアップします。Accelerateは、Mac上のChromeのWeb Audio DSP、FFT、ベクトル数学、およびbiquadフィルター(fft_frame_mac.cc、vector_math_mac.h、biquad.cc、すべてBUILDFLAG(IS_MAC))をバックアップします。特定の呼び出しサイトで間違ったライブラリを選択すると、ほとんどの入力で1 ULPオフになり、偽装しないよりも悪くなります。 4. アーキテクチャが漏洩します。ARMとx86は、融合乗算加算とNaN符号伝播で異なります。紙の上で正しい再現は、コンパイラが一方のターゲットで乗算加算を融合し、もう一方では融合しない場合、ドリフトします。 マップ: 何がどこで漏洩するか ルーティングを1ページにまとめます。太字はホストlibm(glibc、Apple libsystem_m、またはUCRT)であり、OSを漏洩するコードです。それ以外のすべては、すべてのマシンで同一であり、そのままにしておくことができます。 操作 V8 Math.* (JS) CSS calc() Web Audio sin cos tan V8 バンドル ホスト libm Accelerate (osc FFT)、コンプレッサーのスカラー asin acos atan atan2 V8 バンドル ホスト libm 未使用 tanh ホスト libm なし 未使用 exp V8 バンドル ホスト libm コンプレッサーのスカラー log log2 log10 pow V8 バンドル ホスト libm コンプレッサーのスカラー log10f / powf vector add/mul/scale, FFT n/a n/a Accelerate (vDSP) on Mac sqrt abs + - * / ハードウェア ハードウェア ハードウェア V8 バンドル = 静的にリンクされ、すべてのOSで同一: ほとんどの関数はllvm-libc、sin/cosはglibc由来のdbl-64ルーチン。ホスト libm = OSを漏洩するプラットフォームライブラリ(Macではlibsystem_m、Linuxではglibc、WindowsではUCRT)。Accelerate = ChromeがMac Web Audio DSPに使用するAppleのvDSP。 3つの点が際立っています。第一に、V8はほとんどすべてを独自のバンドルされた数学ルーチンで処理するため、JavaScript Mathは正確に1つの場所で信号となります: Math.tanh。第二に、Blinkはすべての三角関数に対してホストlibmを直接呼び出すため、CSSはどこでも信号となります。第三に、Mac上のWeb Audioは、FFTとベクトルステージではAccelerateを実行しますが、DynamicsCompressorのサンプルごとの超越関数はスカラーlibsystem_mのままです。1つのオーディオグラフに3つの異なるライブラリがあります。 WASMは、超越オペコードを持たないため、テーブルに含まれていません。sinなどはモジュールがバンドルしたlibmから来ており、その算術演算(f64.sqrt、f64.mul)はハードウェアなので、WASMの数学はすべてのOSで同一です。その唯一のフィンガープリンティング軸は、NaN正規化といくつかのSIMD丸めにおけるARM対x86の分割です。 信号は3つのサーフェスにクラスター化されています: Math.tanh、すべてのCSS三角関数、およびWeb Audio(CPUアーキテクチャを運ぶAccelerate FFT、およびOSを運ぶコンプレッサーのスカラーlibsystem_m)。それがターゲット全体です。 どのように閉じるか ノイズなし。出力の摂動は2回失敗します。参照比較では、実際のOSのいずれにも一致しない値が表示され、呼び出しごとのランダム性は決定論を壊し、それ自体が信号となります。ターゲットは「Linuxと異なる」ことではありません。ターゲットは「主張するOSと同一」であることです。 アルゴリズムを正確に再現してください。ターゲットのlibmからターゲットのminimax係数、指数テーブル、および削減定数を回復し、それらをポータブルCに転写してください。ターゲットが間違った方向に丸める入力を含め、すべてのビットを一致させてください。あなたは良いtanhを構築しているのではありません。あなたは彼らのものを構築しているのです。これはAppleのsin多項式であり、係数はlibsystem_mから直接抽出されています: // Appleが出力するすべての融合乗算加算は、明示的なfma()として記述されています。 // 各係数のビットパターンはそのままコピーされています。10進表記では丸めが異なります。 static const double P[6] = { 0x1.5d8fd1fd19ccdp-33, -0x