共用方式為


網路驅動程式的安全性問題

如需撰寫安全驅動程式的一般討論,請參閱 建立可靠 Kernel-Mode 驅動程式

除了遵循安全編碼做法和一般裝置驅動程式指引之外,網路驅動程式應執行下列動作來增強安全性:

  • 所有網路驅動程式都應該驗證它們從登錄讀取的值。 具體而言, NdisReadConfigurationNdisReadNetworkAddress 的呼叫端不得對從登錄讀取的值進行任何假設,而且必須驗證它所讀取的每個登錄值。 如果 NdisReadConfiguration 的呼叫端判斷某個值超出界限,則應該改用預設值。 如果 NdisReadNetworkAddress 的呼叫端判斷值超出界限,它應該改用永久的媒體訪問控制 (MAC) 位址或默認位址。

OID 特定問題

查詢 OID 安全性指導方針

大部分的查詢 OID 都可以由系統上的任何使用者模式應用程式發出。 請遵循這些查詢 OID 的特定指導方針。

  1. 請一律驗證緩衝區的大小足以供輸出使用。 沒有輸出緩衝區大小檢查的任何查詢 OID 處理程式都有安全性錯誤。

    if (oid->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) {
        oid->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG);
        return NDIS_STATUS_INVALID_LENGTH;
    }
    
  2. 一律將正確的最小值寫入 BytesWritten。 這是像下列範例一樣指派 oid->BytesWritten = oid->InformationBufferLength 的紅色旗標。

    // ALWAYS WRONG
    oid->DATA.QUERY_INFORMATION.BytesWritten = DATA.QUERY_INFORMATION.InformationBufferLength; 
    

    OS 會將 BytesWritten 位元組複製到 usermode 應用程式。 如果 BytesWritten 大於驅動程式實際撰寫的位元元組數目,則 OS 最終可能會將未初始化的核心記憶體複製到 usermode,這會是資訊洩漏弱點。 請改用類似以下的程式代碼:

    oid->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG);
    
  3. 永不從緩衝區讀取值。 在某些情況下,OID 的輸出緩衝區會直接對應到惡意的使用者模式進程。 在您寫入輸出緩衝區之後,惡意程式可能會變更輸出緩衝區。 例如,下列程式代碼可能會受到攻擊,因為攻擊者可以在撰寫後變更 NumElements:

    output->NumElements = 4;
    for (i = 0 ; i < output->NumElements ; i++) {
        output->Element[i] = . . .;
    }
    

    若要避免從緩衝區讀取,請保留本機複本。 例如,若要修正上述範例,請引進新的堆疊變數:

    ULONG num = 4;
    output->NumElements = num;
    for (i = 0 ; i < num; i++) {
        output->Element[i] = . . .;
    }
    

    使用此方法時,for 迴圈會從驅動程式的堆疊變數 num 讀取回,而不是從其輸出緩衝區讀取。 驅動程式也應該使用 volatile 關鍵詞標記輸出緩衝區,以防止編譯程式以無訊息方式復原此修正程式。

設定 OID 安全性指導方針

大部分的 Set OID 都可以由系統管理員或系統安全組中執行的 usermode 應用程式發出。 雖然這些通常是受信任的應用程式,但迷你埠驅動程式仍然不得允許記憶體損毀或插入核心程序代碼。 請遵循設定 OID 的下列特定規則:

  1. 請一律驗證輸入夠大。 沒有輸入緩衝區大小檢查的任何 OID 集合處理程式都有安全性弱點。

    if (oid->DATA.SET_INFORMATION.InformationBufferLength < sizeof(ULONG)) {
        return NDIS_STATUS_INVALID_LENGTH;
    }
    
  2. 每當使用內嵌位移驗證 OID 時,您必須驗證內嵌緩衝區是否位於 OID 承載內。 這需要數個檢查。 例如, OID_PM_ADD_WOL_PATTERN 可能會提供需要檢查的內嵌模式。 正確驗證需要檢查:

    1. InformationBufferSize >= sizeof (NDIS_PM_PACKET_PATTERN)

      PmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer;
      if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
      {
          Status = NDIS_STATUS_BUFFER_TOO_SHORT;
          *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
          break;
      }
      
    2. Pattern-PatternOffset> + Pattern-PatternSize> 不會溢位

      ULONG TotalSize = 0;
      if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternSize, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      

      這兩個檢查可以使用下列範例的程式代碼來結合:

      ULONG TotalSize = 0;
      if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN) ||
          !NT_SUCCESS(RtlUlongAdd(Pattern->PatternSize, Pattern->PatternOffset, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      
    3. InformationBuffer + Pattern-PatternOffset> + Pattern-PatternLength> 不會溢位

      ULONG TotalSize = 0;
      if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) ||
          (!NT_SUCCESS(RtlUlongAdd(TotalSize, InformationBuffer, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      
    4. Pattern-PatternOffset> + Pattern-PatternLength <>= InformationBufferSize

      ULONG TotalSize = 0;
      if(!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) ||
          TotalSize > InformationBufferLength)) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      

方法 OID 安全性指導方針

方法 OID 可由系統管理員或系統安全組中執行的 usermode 應用程式發出。 它們是集合和查詢的組合,因此上述兩個指引清單也適用於方法 OID。

其他網路驅動程式安全性問題

  • 許多 NDIS 迷你埠驅動程式都會使用 NdisRegisterDeviceEx 公開控制裝置。 這樣做的處理程式必須稽核其 IOCTL 處理程式,且所有的安全性規則都與 WDM 驅動程式相同。 如需詳細資訊,請參閱 I/O 控制程式碼的安全性問題

  • 設計良好的 NDIS 迷你埠驅動程式不應該依賴在特定進程內容中呼叫,也不會與使用者模式 (非常緊密地互動,& OID 是例外狀況) 。 這會是紅色旗標,以查看開啟 usermode 句柄、執行使用者模式等候或針對 usermode 配額配置記憶體的迷你埠。 應該調查該程序代碼。

  • 大部分的 NDIS 迷你埠驅動程式不應涉及剖析封包承載。 不過,在某些情況下,可能需要。 如果是,應該非常仔細地稽核此程式代碼,因為驅動程式正在剖析來自不受信任來源的數據。

  • 如同配置內核模式記憶體時的標準,NDIS 驅動程式應該使用適當的 NX 集區 Opt-In 機制。 在 WDK 8 和更新版本中,函 NdisAllocate* 式系列已正確選擇加入。