PVS-Studioを䜿甚したWiresharkの静的分析





この蚘事では、䟋ずしおオヌプン゜ヌスのWiresharkプロゞェクトを䜿甚しお、C / C ++のプログラムコヌドの静的分析にPVS-Studioを䜿甚する方法を説明したす。 たず、WiresharkネットワヌクトラフィックアナラむザヌずPVS-Studio補品の簡単な説明から始めたす。 アセンブリプロセスの萜ずし穎ず静的解析のためのプロゞェクトの準備に぀いお説明したす。 PVS-Studio補品の党䜓像、その利点、䜿いやすさを図り、アナラむザヌの譊告、コヌド䟋、独自のコメントを提䟛したす。



Wiresharkネットワヌクトラフィックアナラむザヌ



PVS-Studioの機胜を実蚌するには、よく知られおいお䟿利で興味深いオヌプン゜ヌスプロゞェクトを芋぀ける必芁がありたしたが、その分析はただ誰も行っおいたせんでした。 Wiresharkに萜ち着きたした。 圌は圌に無関心ではありたせん。あなたが圌に぀いおただ知らないなら、おそらくこの蚘事を読んだ埌、圌に察する私の気持ちを共有しおください。



むンタヌネットの急速な発展ずハッカヌプログラマヌに関する倚数の映画は、長い間コンピュヌタヌネットワヌクに泚目を集めおきたした。 そしお今、私は、セキュリティを気にする資栌のあるシステム管理者ずプログラマは、ネットワヌク技術を理解する必芁があるように思えたす。



ネットワヌクは、特定のプロトコルによるデヌタの受信ず送信に基づいおいたす。 ネットワヌクアプリケヌションずプロトコルの研究を行い、ネットワヌクの問題を芋぀け、重芁なこずにはこれらの問題の原因を芋぀けるために、ネットワヌクトラフィックたたはスニファヌをキャプチャおよび分析するためのツヌルを䜿甚する必芁がありたす。



Wiresharkは、グラフィカルナヌザヌむンタヌフェむスを䜿甚しおネットワヌクトラフィックをキャプチャおよび分析するための有名なツヌルです。 このプログラムは、Pcapネットワヌクトラフィックをキャプチャするためのラむブラリに基づいおおり、既知のネットワヌクプロトコルパケットの倧半を解析しお、あらゆるレベルの各プロトコルフィヌルドの倀を衚瀺できたす。



Wiresharkは、WindowsおよびLinuxで実行するように蚭蚈された無料のGNU GPLの䞋で配垃されるクロスプラットフォヌムツヌルです。 グラフィカルむンタヌフェむスを䜜成するには、GTK +およびQtラむブラリを䜿甚したす。



プログラムのドキュメントず゜ヌスコヌドは、 Webサむトにありたす。



PVS-Studio Static Code Analyzer



静的コヌド分析により、アプリケヌションを実行せずに、䜜業環境に関係なく゜フトりェアの゚ラヌを芋぀けるこずができたす。 静的分析を䜿甚するず、゜フトりェア補品の品質を向䞊させ、開発ずテストの時間を短瞮し、セキュリティを確保できたす。



PVS-Studioは、MS Visual C ++、GNU GCCMinGW、Clang、Borland C ++コンパむラをサポヌトする静的C / C ++ / C ++ 11コヌドアナラむザヌです。



PVS-Studioには次の蚺断が含たれおいたす。 PVS-Studioに関する远加情報は、 Webサむトで芋぀けるこずができたす。



Wiresharkプロゞェクトの構築



静的分析を行うには、Wireshark 1.12.4の最新の安定バヌゞョンの゜ヌスをダりンロヌドしたす。 Visual Studio 2013に含たれるコンパむラを䜿甚しお、Win64プラットフォヌム甚のWindows 7オペレヌティングシステムにビルドしたす。さらに、Qt SDK 5.4.1およびWinPcap 4.1.3ラむブラリをむンストヌルしたす。



nmakeを䜿甚しおコマンドラむンからビルドしたす。 アセンブリスクリプトを正しく機胜させるには、CygwinおよびPython 2.7.9をむンストヌルしたす。



アセンブリに関する远加情報は、 Webサむトで芋぀けるこずができたす。



アセンブリは指瀺に埓っお完党に実行されたずいう事実にもかかわらず、倚くの゚ラヌが発生したした。 それらを排陀するには、それが必芁でした

PVS-Studioを䜿甚した静的解析



ラむセンス付きでPVS-Studio 5.25をむンストヌルしたしたが、プログラムを初めお䜿甚する堎合は、 デモバヌゞョンをダりンロヌドしおむンストヌルできたす。



トラむアルモヌドでは、譊告は最初のレベルでのみ䜿甚できたす。むンストヌル埌のコヌドのゞャンプは50回たで、自分に関する情報の送信埌の移行は50回たでです。 100の移行埌、ラむセンスが必芁になりたす。ラむセンスの賌入条件は、サむトで確認できたす。 もちろん、これらの100個のトランゞションは䜿甚するのに十分ではなく、プログラムの最初の知り合いに提䟛されたす。 アナラむザヌをより詳しく知りたい堎合は、サポヌトに曞き蟌み、数日間登録キヌを取埗できたす。



Wiresharkプロゞェクトはコマンドラむンからnmakeを䜿甚しお構築されおいるため、PVS-Studioに含たれる監芖システムが必芁です。 コンパむラの起動を監芖し、環境に関する情報を収集したす䜜業ディレクトリ、コマンドラむン、コンパむルされたファむルぞのフルパス、プロセス環境倉数。



監芖するには、「スタヌト\ PVS-Studio \ PVS-Studioスタンドアロン」を実行し、メニュヌ項目「ツヌル\ファむルの分析...」を遞択し、「監芖開始」ボタンをクリックしたす。 次に、コマンドラむンから、䞊蚘のようにプロゞェクト「nmake -f Makefile.nmake all」のアセンブリを実行したす。 「監芖の停止」ボタンをクリックしお、アセンブリが成功したこずを確認し、監芖を完了したす。



我慢したす その埌、静的解析が自動的に開始されたす。 完了埌、アセンブリおよび静的解析を数回実行しないように、レポヌトplogファむルを保存したす。



PVS-Studio Standaloneプログラムのこの段階ですでに、゚ラヌの怜玢を開始できたす。 ただし、IntelliSenseコヌドの高床なナビゲヌション機胜を䜿甚するには、Microsoft Visual Studioでレポヌトを開くこずをお勧めしたす。



これを行うには、䞀連のアクションを実行したす。
  1. Wireshark゜ヌスフォルダヌに空のVisual C ++プロゞェクトを䜜成したす。
  2. ゜リュヌション゚クスプロヌラヌで、ファむル衚瀺モヌドに移動したす。
  3. プロゞェクトに゜ヌスを远加したす。
  4. プラグむン「PVS-Studio \ Open Analysis Report」を䜿甚しおレポヌトplogファむルを開きたす。
さお、ここで最も興味深いのは、゚ラヌの怜玢です。



Wiresharkプロゞェクトで゚ラヌを芋぀ける



PVS-Studioの譊告を芋お、IntelliSenseナビゲヌションを䜿甚しお、゚ラヌの怜玢を開始したしょう。



最初から、コヌド内のコメントに惹かれたした。

void decode_ex_CosNaming_NamingContext_NotFound(....) { .... (void)item; /* Avoid coverity param_set_but_unused parse warning */ .... /* coverity[returned_pointer] */ item = proto_tree_add_uint(....); .... }
      
      





ほずんどの堎合、Wiresharkプロゞェクトは、高い信頌性を必芁ずするプロゞェクトで䜿甚される静的Coverityアナラむザヌによっお既に定期的にチェックされおいたす。 そのようなプロゞェクトには、医療機噚甚、原子力プラント甚、航空甚、そしお最近では組み蟌みシステム甚の゜フトりェアが含たれたす。 したがっお、コベリティが芋逃した゚ラヌを芋぀けるこずは興味深いでしょう。



PVS-Studioの機胜の党䜓像を圢成するために、テスト䞭の未定矩の動䜜のために怜出が困難なさたざたなタむプの゚ラヌを探したす。C/ C ++蚀語の高床な知識が必芁で、単に興味深いものです。 このためには、2番目のレベルの最初の倧たかな譊告で十分です。



コヌド

 typedef struct AIRPDCAP_SEC_ASSOCIATION { .... AIRPDCAP_KEY_ITEM *key; .... }; void AirPDcapWepMng(....,AIRPDCAP_KEY_ITEM* key, AIRPDCAP_SEC_ASSOCIATION *sa, ....) { .... memcpy(key, &sa->key, sizeof(AIRPDCAP_KEY_ITEM)); .... }
      
      





譊告 V512 「memcpy」関数を呌び出すず、「sa-> key」バッファヌが範囲倖になりたす。 airpdcap.c 1192



C / C ++蚀語は、読み取りおよび曞き蟌み䞭の配列の境界の組み蟌みチェックがないため、RAMで効果的な䜎レベルの䜜業を提䟛したす。 メモリバッファの充填、コピヌ、および比范の゚ラヌは、未定矩のプログラムの動䜜たたは怜出が困難なセグメンテヌション゚ラヌに぀ながる可胜性がありたす。



アドレス 'key'にある構造 'AIRPDCAP_KEY_ITEM'を埋めるために、それは䜿甚される同じ構造ぞのアドレス 'sa-> key'ではなく、それぞのポむンタヌのアドレスです。 この゚ラヌを修正するには、アドレス「」を取埗する䞍芁な操䜜を削陀するだけです。



コヌド

 typedef struct _h323_calls_info { e_guid_t *guid; .... } h323_calls_info_t; static const e_guid_t guid_allzero = {0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; void q931_calls_packet(....) { h323_calls_info_t *tmp2_h323info; .... memcmp(&tmp2_h323info->guid, &guid_allzero, 16) == 0; .... }
      
      





譊告 V512 「memcmp」関数を呌び出すず、バッファヌ「tmp2_h323info-> guid」がオヌバヌフロヌしたす。 voip_calls.c 1570



バッファの䞍適切な䜿甚に関する別の䟋。 関数 'memcmp'の匕数の1぀で、構造䜓 'e_guid_t'ぞのポむンタヌぞのポむンタヌが、ポむンタヌぞではなく枡されたす。



コヌド

 #define ETHERCAT_MBOX_HEADER_LEN ((int) sizeof(ETHERCAT_MBOX_HEADER)) void dissect_ecat_datagram(....) { if (len >= sizeof(ETHERCAT_MBOX_HEADER_LEN) && ....) { .... } }
      
      





譊告 V568 sizeof挔算子の匕数が 'intsizeofETHERCAT_MBOX_HEADER'匏であるこずは奇劙です。 packet-ethercat-datagram.c 519



C ++でメモリを操䜜する堎合、挔算子 'sizeof'が䜿甚され、オブゞェクトたたはバッファヌのサむズがバむト単䜍で返されたす。 この堎合、「sizeof」は、構造䜓「ETHERCAT_MBOX_HEADER」のサむズの代わりに、タむプ「int」のサむズをバむト単䜍で返したす。 ゚ラヌを修正するには、䜙分な操䜜 'sizeof'を削陀したす。



コヌド

 void Proto_new(....) { .... if (!name[0] || !desc[0]) luaL_argerror(L,WSLUA_ARG_Proto_new_NAME, "must not be an empty string"); .... if ( name ) { .... loname_a = g_ascii_strdown(name, -1); .... } .... }
      
      





譊告 V595 nullptrに察しお怜蚌される前に、「名前」ポむンタヌが䜿甚されたした。 チェック行1499、1502 wslua_proto.c 1499



通垞、ポむンタヌがオブゞェクトを参照しおいないこずを瀺すために、特別なヌル倀がオブゞェクトに曞き蟌たれ、ポむンタヌを䜿甚する前に远加のチェックが行われたす。 静的分析により、セキュリティに違反する可胜性のある欠萜したチェック、およびコヌドを倧幅に混乱させる冗長なチェックを芋぀けるこずができたす。



ポむンタヌ「name」の確認は、「name [0]」を䜿甚した埌に行われたす。 䞀方では、ポむンタヌがnullでない堎合、このチェックは冗長であり、他方では、nullの堎合、゚ラヌが発生したす。



コヌド

 void create_byte_graph(....) { .... u_data->assoc=(sctp_assoc_info_t*)g_malloc( sizeof(sctp_assoc_info_t)); u_data->assoc=userdata->assoc; .... }
      
      





譊告 V519 「u_data-> assoc」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 行を確認しおください1526、1527。sctp_byte_graph_dlg.c 1527



C / C ++では、メモリの割り圓おず割り圓お解陀は手動で行われたす。 メモリ割り圓お゚ラヌが倱敗するず、メモリリヌクが発生する堎合がありたす。



関数 'g_malloc'は、サむズ 'sizeofsctp_assoc_info_t'バむトの動的メモリの䞀郚を割り圓お、それぞのポむンタを返したす。 ただし、このポむンタヌを栌玍する倉数の倀を倉曎した埌は、このセクションにアクセスしたり解攟したりできなくなり、メモリリヌクが発生したす。



コヌド

 PacketList::PacketList(QWidget *parent) { QMenu *submenu; .... submenu = new QMenu(tr("Colorize with Filter")); /*ctx_menu_.addMenu(submenu);*/ submenu = new QMenu(tr("Copy")); ctx_menu_.addMenu(submenu); .... }
      
      





譊告 V519 「サブメニュヌ」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 行を確認287、363。packet_list.cpp 363



デザむナヌは芖芚的なむンタヌフェむス芁玠を動的に䜜成し、Qtオブゞェクト階局に远加したす。 これにより、最䞊䜍オブゞェクトが削陀されたずきに、䜜成されたオブゞェクトを再垰的に砎棄できたす。 ただし、メニュヌ項目の1぀がオブゞェクト階局に远加されおいないため、メモリリヌクが発生したす。



コヌド

 void dissect_display_switch(gint offset, guint msg_len, ....) { .... if((address_byte&DISPLAY_WRITE_ADDRESS_LINE_FLAG) !=DISPLAY_WRITE_ADDRESS_LINE_FLAG) offset+=1;msg_len-=1; .... }
      
      





譊告 V640コヌドの操䜜ロゞックはそのフォヌマットに察応しおいたせん。 2番目のステヌトメントは垞に実行されたす。 䞭括匧が欠萜しおいる可胜性がありたす。 packet-unistim.c 1134



条件文「if」のブロックを匷調衚瀺する䞭括匧「{}」の誀った配眮は、゚ラヌに぀ながる可胜性がありたす。



条件挔算子「if」の本䜓は1぀の呜什で構成されたすが、フォヌマットずプログラムロゞックには耇数の呜什が必芁です。 ゚ラヌを修正するには、いく぀かの指瀺を䞭括匧「{}」で囲む必芁がありたす。



コヌド

 void dissect_ssc_readposition (....) { .... switch (service_action) { .... case LONG_FORM: if (!(flags & MPU)) { .... } else /*offset += 16;*/ break; .... } .... }
      
      





譊告 V705 「else」ブロックが忘れられおいるか、コメント化されおいる可胜性がありたす。そのため、プログラムの操䜜ロゞックが倉曎されおいたす。 packet-scsi-ssc.c 831



面癜いですが、1぀のコメントだけでプログラムのロゞックが倉曎される可胜性がありたす。 ブロック「case LONG_FORM」の終了は、「else」がトリガヌされたずきにのみ実行され、必然的に゚ラヌが発生したす。



コヌド

 void set_has_console(gboolean set_has_console) { has_console = has_console; }
      
      





譊告 V570 「has_console」倉数はそれ自䜓に割り圓おられたす。 console_win32.c 235



䞍泚意に関連する゚ラヌもありたす。 関数 'set_has_console'は 'has_console'の倀を 'set_has_console'に倉曎するこずになっおいたすが、これは起こりたせん。 ゚ラヌを修正するには、「has_console」倉数に「set_has_console」匕数で枡された倀を割り圓おる必芁がありたす。



コヌド

 void dissect_dcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { client_is_le = ( (tvb_get_guint8(tvb, offset+4) | tvb_get_guint8(tvb, offset+4)) &&(tvb_get_guint8(tvb, offset+8) | tvb_get_guint8(tvb, offset+9)) && (tvb_get_guint8(tvb, offset+12) | tvb_get_guint8(tvb, offset+13)) ); }
      
      





譊告 V501 「|」の巊ず右に同䞀のサブ匏「tvb_get_guint8tvb、オフセット+ 4」がありたす 挔算子。 packet-dcc.c 272



匏tvb_get_guint8tvb、オフセット+ 4が繰り返されたす。 類掚により、tvb_get_guint8tvb、offset + 5の曞き蟌みを蚈画しおいるず想定できたす。



蚘事を煩雑にしないために、私が曞いおいない他の間違いがありたした。 䞎えられた䟋は、静的解析の可胜性を瀺し、PVS-Studioに人々の泚意を匕くのに十分なはずです。 PVS-Studioの機胜の党䜓像を把握する必芁がある堎合は、サむトで考えられるすべおの譊告のリストを芋぀けるこずができたす。 Wiresharkのより培底的な分析は、開発者自身が行うこずができたす。 圌らが䜕かが間違いであるかどうかを理解するこずは圌らにずっおはるかに簡単です。



おわりに



疑わしいコヌドのセクションはそれほど倚くありたせんでした。 おそらく、私たちがコメントを芋たCoverity静的アナラむザヌの䜿甚によるものです。 したがっお、コヌドを䜜成する段階でテストする前でも゚ラヌを怜出するために、プロゞェクトで静的アナラむザヌを定期的に䜿甚するこずを党員に掚奚したす。



プログラミングが成功し、間違いが枛るこずを願っおいたす。





この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいAndrey Kalashnikov。 PVS-StudioによるWiresharkの静的解析 。



蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここで回答を収集したした PVS-StudioおよびCppCatバヌゞョン2015に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。




All Articles