# Solidityコンパイラの脆弱性解析と対策コンパイラは現代のコンピュータシステムの基本コンポーネントの1つであり、その主な機能は高級プログラミング言語のソースコードをコンピュータの低レベルCPUまたは仮想マシンが実行可能な命令コードに変換することです。ほとんどの開発者やセキュリティ専門家が通常アプリケーションコードの安全性により関心を持っている一方で、コンパイラ自体の安全性も同様に重要です。コンピュータプログラムとして、コンパイラにもセキュリティの脆弱性が存在する可能性があり、場合によっては深刻な安全リスクをもたらすことがあります。ブラウザを例にとると、JavaScriptフロントエンドコードのコンパイルと実行の過程で、JavaScript解析エンジンの脆弱性により、ユーザーが悪意のあるウェブページにアクセスした際に攻撃者がその脆弱性を利用してリモートコード実行を実現し、最終的に被害者のブラウザや場合によってはオペレーティングシステムを制御することがあります。さらに、C++コンパイラのバグもリモートコード実行などの深刻な結果を引き起こす可能性があります。Solidityコンパイラにも安全上の脆弱性があります。Solidity開発チームのセキュリティ警告によると、複数のバージョンのSolidityコンパイラに安全上の脆弱性が存在します。! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/social/moments-7d1e882c0b106528437910218bf21f82)## Solidityコンパイラの脆弱性Solidityコンパイラの役割は、スマートコントラクトコードをEthereum仮想マシン(EVM)の命令コードに変換することです。これらの命令コードは、取引を通じてパッケージ化されEthereumにアップロードされ、最終的にEVMによって解析され実行されます。注意すべきは、Solidityコンパイラの脆弱性とEVM自体の脆弱性は異なるということです。EVMの脆弱性は、仮想マシンが命令を実行する際に発生するセキュリティ問題であり、Ethereumネットワーク全体に影響を与える可能性があります。一方、Solidityコンパイラの脆弱性は、SolidityをEVMコードに変換する際に存在する問題であり、Ethereumネットワーク自体には直接影響を与えません。Solidityコンパイラの脆弱性の一つの危険性は、生成されたEVMコードがスマートコントラクト開発者の期待と一致しない可能性があることです。Ethereum上のスマートコントラクトは通常、ユーザーの暗号通貨資産と関連しているため、コンパイラによって引き起こされるバグはユーザー資産の損失を招く可能性があり、深刻な結果をもたらすことがあります。開発者や契約監査者は、契約コードの論理実装の問題や、再入、整数オーバーフローなどのSolidityレベルのセキュリティ問題に重点を置くかもしれません。しかし、Solidityコンパイラの脆弱性については、契約のソースコードの論理監査だけでは発見するのが難しいです。特定のコンパイラのバージョンと特定のコードパターンを組み合わせて分析する必要があります。そうすることで、スマートコントラクトがコンパイラの脆弱性の影響を受けているかどうかを判断できます。## Solidityコンパイラの脆弱性の例以下は、具体的な形態、原因、危害を示すいくつかの実際のSolidityコンパイラの脆弱性の例です。### SOL-2016-9 ハイオーダーバイトクリーンストレージこの脆弱性は、以前のバージョンのSolidityコンパイラに存在します(>=0.1.6 <0.4.4)。次のコードを考えてください:ソリディティコントラクトC { uint32 a = 0x12345678; uint32 b = 0; function run() は (uint256) { を返します。 a += 1; bを返す; }}storage変数bは何の変更もされていないため、run()関数はデフォルト値0を返すべきです。しかし、脆弱性のあるバージョンのコンパイラが生成したコードでは、run()は1を返します。この期待に反する状況は、b変数が権限検証や資産記帳などの目的で使用される場合、深刻な結果を引き起こす可能性があります。このような状況が発生する原因は、EVMが32バイトのサイズのスタック要素を使用しているのに対し、Solidityがuint32などの小さなデータ型をサポートしているためです。コンパイラはこれらの型を処理する際に上位ビットをクリアする操作を行う必要がありますが、整数オーバーフローが発生した際に正しく処理されず、上位ビットの1ビットが隣接するb変数に書き込まれてしまいます。### SOL-2022-4 インラインアセンブリメモリ副作用この脆弱性は0.8.13から0.8.15バージョンのコンパイラに存在します。以下のコードを考慮してください:ソリディティコントラクトC { function f() public pure は (uint) { を返します。 アセンブリ{ mstore(0, 0x42) } uint x; アセンブリ { x := mload(0) } xを返す; }}この脆弱性は、コンパイル最適化操作に起因します。コンパイラは、単一のアセンブリブロックを分析して最適化を行いますが、あるメモリ書き込み操作がその後読み取られない場合、ガスを節約するためにその操作を削除します。しかし、上記のコードでは、メモリの書き込みと読み取りが異なる二つのアセンブリブロックに存在しており、コンパイラは最初の書き込みを冗長であると誤って判断し、それを削除してしまいます。その結果、f()関数は正しい0x42ではなく0を返します。### SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanupこの脆弱性は、0.5.8から0.8.16までのバージョンのコンパイラに影響を与えます。次のコードを考えてください:ソリディティコントラクトC { function f(bytes4[] calldata a) external pure 戻り値 (bytes4[] memory) { abi.decode(abi.encode(a), (bytes4[])); }}通常、このコードは入力されたa変数を返すべきです。しかし、脆弱性のあるバージョンでは、"aaaa"を入力すると空の配列が返されます。これは、Solidityがcalldata型の配列にabi.encode操作を行う際に、誤っていくつかのデータをクリーニングし、隣接データを変更したため、エンコードおよびデコード後のデータが不一致になることが原因です。注目すべきは、Solidityがexternal callとemit eventを行う際に、パラメータを暗黙的にabi.encodeするため、この種の脆弱性が発生する確率は想像以上に高くなる可能性があることです。! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/social/moments-c97428f89ed62d5ad8551cdb2ba30867)## セキュリティの推奨事項Solidityコンパイラの脆弱性に対して、開発者とセキュリティ担当者に以下の提案を行います:開発者向け:- より新しいバージョンのSolidityコンパイラーを使用してください。新しいバージョンは通常、既知のセキュリティ問題を修正しています。- ユニットテストケースを充実させる。ほとんどのコンパイラレベルのバグは、コードの実行結果が予想と一致しない原因となるため、テストカバレッジを向上させることでこのような問題を最大限に回避できる。- インラインアセンブリや複雑なABIのエンコード・デコードなどの操作はできるだけ避け、新しい機能や実験的な機能を盲目的に使用しないでください。ほとんどのコンパイラの脆弱性はこれらの複雑な操作に関連しています。セキュリティ担当者向け:- Solidityコードの監査を行う際、コンパイラがもたらす可能性のあるセキュリティリスクを無視しないでください。- 内部開発プロセスにおいて、開発チームにSolidityコンパイラのバージョンをアップグレードするよう促し、CI/CDプロセスにコンパイラバージョンの自動チェックを導入することを検討できます。- コンパイラの脆弱性について過度に心配する必要はありません。ほとんどの脆弱性は特定のコードパターンでのみ発生し、具体的なプロジェクトの状況に応じて実際の影響を評価する必要があります。いくつかの実用的なリソース:- Solidityチームが定期的に発表するセキュリティ警告- Solidity公式リポジトリの定期的に更新されるバグリスト- 各バージョンコンパイラのバグリスト- Etherscanの契約コードページ右上隅の三角形の感嘆符は、現在のバージョンのコンパイラに存在するセキュリティの脆弱性を示すことができます。! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/social/moments-84f5083d8748f2aab71fd92671d999a7)以上のように、Solidityコンパイラの脆弱性はスマートコントラクト開発において無視できないセキュリティリスクです。開発者とセキュリティ担当者は警戒を強め、これらの脆弱性による潜在的な脅威を軽減するための適切な対策を講じるべきです。
Solidityコンパイラの脆弱性解析と対策
Solidityコンパイラの脆弱性解析と対策
コンパイラは現代のコンピュータシステムの基本コンポーネントの1つであり、その主な機能は高級プログラミング言語のソースコードをコンピュータの低レベルCPUまたは仮想マシンが実行可能な命令コードに変換することです。
ほとんどの開発者やセキュリティ専門家が通常アプリケーションコードの安全性により関心を持っている一方で、コンパイラ自体の安全性も同様に重要です。コンピュータプログラムとして、コンパイラにもセキュリティの脆弱性が存在する可能性があり、場合によっては深刻な安全リスクをもたらすことがあります。
ブラウザを例にとると、JavaScriptフロントエンドコードのコンパイルと実行の過程で、JavaScript解析エンジンの脆弱性により、ユーザーが悪意のあるウェブページにアクセスした際に攻撃者がその脆弱性を利用してリモートコード実行を実現し、最終的に被害者のブラウザや場合によってはオペレーティングシステムを制御することがあります。さらに、C++コンパイラのバグもリモートコード実行などの深刻な結果を引き起こす可能性があります。
Solidityコンパイラにも安全上の脆弱性があります。Solidity開発チームのセキュリティ警告によると、複数のバージョンのSolidityコンパイラに安全上の脆弱性が存在します。
! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/webp-social/moments-7d1e882c0b106528437910218bf21f82.webp)
Solidityコンパイラの脆弱性
Solidityコンパイラの役割は、スマートコントラクトコードをEthereum仮想マシン(EVM)の命令コードに変換することです。これらの命令コードは、取引を通じてパッケージ化されEthereumにアップロードされ、最終的にEVMによって解析され実行されます。
注意すべきは、Solidityコンパイラの脆弱性とEVM自体の脆弱性は異なるということです。EVMの脆弱性は、仮想マシンが命令を実行する際に発生するセキュリティ問題であり、Ethereumネットワーク全体に影響を与える可能性があります。一方、Solidityコンパイラの脆弱性は、SolidityをEVMコードに変換する際に存在する問題であり、Ethereumネットワーク自体には直接影響を与えません。
Solidityコンパイラの脆弱性の一つの危険性は、生成されたEVMコードがスマートコントラクト開発者の期待と一致しない可能性があることです。Ethereum上のスマートコントラクトは通常、ユーザーの暗号通貨資産と関連しているため、コンパイラによって引き起こされるバグはユーザー資産の損失を招く可能性があり、深刻な結果をもたらすことがあります。
開発者や契約監査者は、契約コードの論理実装の問題や、再入、整数オーバーフローなどのSolidityレベルのセキュリティ問題に重点を置くかもしれません。しかし、Solidityコンパイラの脆弱性については、契約のソースコードの論理監査だけでは発見するのが難しいです。特定のコンパイラのバージョンと特定のコードパターンを組み合わせて分析する必要があります。そうすることで、スマートコントラクトがコンパイラの脆弱性の影響を受けているかどうかを判断できます。
Solidityコンパイラの脆弱性の例
以下は、具体的な形態、原因、危害を示すいくつかの実際のSolidityコンパイラの脆弱性の例です。
SOL-2016-9 ハイオーダーバイトクリーンストレージ
この脆弱性は、以前のバージョンのSolidityコンパイラに存在します(>=0.1.6 <0.4.4)。
次のコードを考えてください:
ソリディティ コントラクトC { uint32 a = 0x12345678; uint32 b = 0; function run() は (uint256) { を返します。 a += 1; bを返す; } }
storage変数bは何の変更もされていないため、run()関数はデフォルト値0を返すべきです。しかし、脆弱性のあるバージョンのコンパイラが生成したコードでは、run()は1を返します。
この期待に反する状況は、b変数が権限検証や資産記帳などの目的で使用される場合、深刻な結果を引き起こす可能性があります。
このような状況が発生する原因は、EVMが32バイトのサイズのスタック要素を使用しているのに対し、Solidityがuint32などの小さなデータ型をサポートしているためです。コンパイラはこれらの型を処理する際に上位ビットをクリアする操作を行う必要がありますが、整数オーバーフローが発生した際に正しく処理されず、上位ビットの1ビットが隣接するb変数に書き込まれてしまいます。
SOL-2022-4 インラインアセンブリメモリ副作用
この脆弱性は0.8.13から0.8.15バージョンのコンパイラに存在します。
以下のコードを考慮してください:
ソリディティ コントラクトC { function f() public pure は (uint) { を返します。 アセンブリ{ mstore(0, 0x42) } uint x; アセンブリ { x := mload(0) } xを返す; } }
この脆弱性は、コンパイル最適化操作に起因します。コンパイラは、単一のアセンブリブロックを分析して最適化を行いますが、あるメモリ書き込み操作がその後読み取られない場合、ガスを節約するためにその操作を削除します。しかし、上記のコードでは、メモリの書き込みと読み取りが異なる二つのアセンブリブロックに存在しており、コンパイラは最初の書き込みを冗長であると誤って判断し、それを削除してしまいます。その結果、f()関数は正しい0x42ではなく0を返します。
SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup
この脆弱性は、0.5.8から0.8.16までのバージョンのコンパイラに影響を与えます。
次のコードを考えてください:
ソリディティ コントラクトC { function f(bytes4[] calldata a) external pure 戻り値 (bytes4[] memory) { abi.decode(abi.encode(a), (bytes4[])); } }
通常、このコードは入力されたa変数を返すべきです。しかし、脆弱性のあるバージョンでは、"aaaa"を入力すると空の配列が返されます。
これは、Solidityがcalldata型の配列にabi.encode操作を行う際に、誤っていくつかのデータをクリーニングし、隣接データを変更したため、エンコードおよびデコード後のデータが不一致になることが原因です。
注目すべきは、Solidityがexternal callとemit eventを行う際に、パラメータを暗黙的にabi.encodeするため、この種の脆弱性が発生する確率は想像以上に高くなる可能性があることです。
! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/webp-social/moments-c97428f89ed62d5ad8551cdb2ba30867.webp)
セキュリティの推奨事項
Solidityコンパイラの脆弱性に対して、開発者とセキュリティ担当者に以下の提案を行います:
開発者向け:
セキュリティ担当者向け:
いくつかの実用的なリソース:
! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/webp-social/moments-84f5083d8748f2aab71fd92671d999a7.webp)
以上のように、Solidityコンパイラの脆弱性はスマートコントラクト開発において無視できないセキュリティリスクです。開発者とセキュリティ担当者は警戒を強め、これらの脆弱性による潜在的な脅威を軽減するための適切な対策を講じるべきです。