未定義行為 Sanitizer

UndefinedBehaviorSanitizer (UBSan) 會執行編譯時間檢測作業 檢查是否有各種未定義行為雖然 UBSan 能夠 偵測中 許多 未定義行為錯誤,Android 支援:

  • 對齊
  • 布林值
  • 界限
  • 列舉
  • float-cast-overflow
  • 浮點數除以零
  • 整數除以零
  • 非空值屬性
  • null
  • 回傳
  • return-非空值-屬性
  • Shift-base
  • 偏移指數
  • 帶正負號整數溢位
  • 無法連上
  • 無正負號整數溢位
  • Vla 繫結

無正負號整數溢位,在技術上沒有定義 會包含在清理程式中,並用於許多 Android 模組中 包括媒體伺服器元件,藉此消除任何潛在整數溢位現象 安全漏洞

實作

在 Android 建構系統中,您可以針對全域或本機啟用 UBSan。啟用方式 全球 UBSan,請在 Android.mk 中設定 SANITIZE_TARGET。如要在 為每個模組層級設定 LOCAL_SANITIZE,並指定未定義的行為, 您要在 Android.mk 中尋找。例如:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0

LOCAL_SRC_FILES:= sanitizer-status.c

LOCAL_MODULE:= sanitizer-status

LOCAL_SANITIZE := alignment bounds null unreachable integer
LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer

include $(BUILD_EXECUTABLE)

對應的藍圖 (Android.bp) 設定:

cc_binary {

    cflags: [
        "-std=c11",
        "-Wall",
        "-Werror",
        "-O0",
    ],

    srcs: ["sanitizer-status.c"],

    name: "sanitizer-status",

    sanitize: {
        misc_undefined: [
            "alignment",
            "bounds",
            "null",
            "unreachable",
            "integer",
        ],
        diag: {
            misc_undefined: [
                "alignment",
                "bounds",
                "null",
                "unreachable",
                "integer",
            ],
        },
    },

}

UBSan 快速鍵

Android 還有兩個快速鍵:integerdefault-ub,同時啟用一組消毒液。整數 啟用 integer-divide-by-zerosigned-integer-overflowunsigned-integer-overflowdefault-ub 可啟用編譯器最少的檢查作業 效能問題:bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound。 整數清理程式類別可以與 SANITIZE_TARGET 和 LOCAL_SANITIZE、 但 default-ub 只能與 SANITIZE_TARGET 搭配使用。

改善錯誤報告功能

Android 的預設 UBSan 實作會在出現以下情況時叫用指定函式: 發生未定義的行為根據預設,系統會取消此函式。不過 自 2016 年 10 月起,Android 上的 UBSan 將會提供選用的執行階段程式庫。 可提供更詳盡的錯誤報告,包括未定義行為的類型 取得檔案和原始碼行資訊如何啟用這個錯誤 包含整數檢查的報表,在 Android.mk 檔案中加入以下內容:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

LOCAL_SANITIZE 值會在建構期間啟用清理工具。 LOCAL_SANITIZE_DIAG 開啟指定清潔器的診斷模式。是 可以將 LOCAL_SANITIZE 和 LOCAL_SANITIZE_DIAG 設為不同的值,但 只有 LOCAL_SANITIZE 中的檢查啟用。如果未在 LOCAL_SANITIZE,不過在 LOCAL_SANITIZE_DIAG 中指定,因此檢查並未啟用 不會傳送診斷訊息

以下範例為 UBSan 執行階段程式庫提供的資訊:

pixel-xl:/ # sanitizer-status ubsan
sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')

整數溢位清理

非預期的整數溢位現象可能會導致記憶體損毀或資訊 洩漏與記憶體存取相關變數的漏洞 記憶體配置作業為解決這個問題,我們新增了 Clang 的 UndefinedBehaviorSanitizer (UBSan) 會將帶正負號和無正負號的整數溢位掃毒程式 強化 Android 7.0 中的媒體架構。在 Android 9 中 已展開 UBSan 可涵蓋更多元件和改善的建構系統支援。

設計目的是新增算術檢查 及指示,這可能會 溢位—在發生溢位時安全地取消處理程序。 這些清理程式可緩解整個類別的記憶體毀損問題 ,且資訊外洩安全漏洞的根本原因為整數 像是原始 Stagefright 漏洞

範例和來源

整數溢位清理 (IntSan) 是由編譯器提供,並將 在編譯期間檢測二進位檔,藉此偵測算術 溢位。根據預設,系統會為整個 平台 /platform/external/libnl/Android.bp

實作

IntSan 使用 UBSan 的帶符號和無正負號整數溢位清理器。這個 您必須在個別模組層級啟用因應措施。這有助於 ,請勿停用。

強烈建議您啟用「整數溢位清理」功能, 元件。應能使用特殊權限的原生程式碼或原生程式碼 剖析不受信任的使用者輸入內容。在應用程式上 並仰賴程式碼使用情形和 算術運算子預期負擔的比率很小,並測試 效能則不重要

支援 makefiles 中的 IntSan

如要在 makefile 中啟用 IntSan,請新增以下資訊:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE 會取得以半形逗號分隔的消毒液清單。 integer_overflow 是一組預先封裝的選項 個別帶正負號和不帶正負號的整數溢位掃毒程式 預設 封鎖清單
  • LOCAL_SANITIZE_DIAG開啟了以下裝置的診斷模式: 消毒液僅於測試期間使用診斷模式,因為此模式不會 因溢位而取消,完全否定了 以及緩解措施請參閱疑難排解 瞭解詳情。
  • LOCAL_SANITIZE_BLOCKLIST 可讓您指定 BLOCKLIST 檔案,防止函式和來源檔案受到清理。詳情請見 疑難排解, 詳細資料。

如果您需要更精細的控制,請逐一啟用衛生器 或同時標記:

LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
    LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow

支援在藍圖檔案中的 IntSan

如要在藍圖檔案中啟用整數溢位清理功能,例如 /platform/external/libnl/Android.bp、 新增:

   sanitize: {
          integer_overflow: true,
          diag: {
              integer_overflow: true,
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

和 make 檔案一樣,integer_overflow 屬性為預先封裝的套件 個別帶正負號和無正負號整數溢位的選項組合 帶有預設值的消毒液 BLOCKLIST

diag 屬性集啟用診斷模式, 消毒液只在測試期間使用診斷模式。診斷模式不支援 因溢位而取消,完全抵消溢位 以及改進使用者版本詳情請參閱疑難排解

BLOCKLIST 屬性允許指定 BLOCKLIST 檔案 可讓開發人員防止函式和來源檔案 消毒。請參閱疑難排解,瞭解 來瞭解詳情。

如要個別啟用消毒液,請使用:

   sanitize: {
          misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"],
          diag: {
              misc_undefined: ["signed-integer-overflow",
                               "unsigned-integer-overflow",],
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

疑難排解

如要在新元件中啟用整數溢位清理功能,或依賴 含有整數溢位清理功能的平台程式庫,您可能會遇到 有幾個問題會導致良性整數溢位現象導致取消。建議您測試 啟用防毒功能,確保無益的溢位

如要尋找使用者建構作業中受到清除作業所導致的中止情形,請搜尋「 SIGABRT 當機,並顯示取消訊息表示偵測到溢位現象 由 UBSan 提供,例如:

pid: ###, tid: ###, name: Binder:###  >>> /system/bin/surfaceflinger <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: sub-overflow'

不過,堆疊追蹤應包含導致取消作業的函式, 內嵌函式中發生的溢位可能在堆疊追蹤中不見得明顯。

如要輕鬆找出根本原因,請在程式庫中啟用診斷功能 觸發取消並嘗試重現錯誤。有了 診斷結果啟用時,程序不會取消,而會改為 才能繼續執行不取消有助於最大化 安裝好所有錯誤之後,不必重新編譯。 診斷功能會產生錯誤訊息,其中包括行數和來源。 檔案導致取消:

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')

找到有問題的算術作業後,請確認溢位 是良性的,且意味著(例如不會對安全性造成影響)。您可以在 消毒液出借方:

  • 重構程式碼以避免溢位 (範例)
  • 透過 Clang 的 __builtin_*_overflow 明確溢位 函式 (範例)
  • 透過指定 no_sanitize 屬性,在函式中停用清理作業 (範例)
  • 透過 BLOCKLIST 檔案停用函式或來源檔案的清理作業 (範例)

請盡可能使用最精細的解決方案。舉例來說 含有多項算術運算和單一溢位運算的函式 應重構單一作業,而非整個函式 已封鎖。

可能導致良性溢位的常見模式包括:

  • 隱含 轉換,在系統將其轉換為已簽署的類型之前,發生未簽署的溢位 (範例)
  • 連結清單刪除作業,在刪除時減少迴圈索引 (範例)
  • 指派未簽署的類型為 -1,而不是指定實際的最大值 (範例)
  • 迴圈中減少無正負號整數 (example範例)

建議開發人員確保掃毒程式偵測到這種情況 其為良性的溢位,沒有任何非預期的副作用或安全性

停用 IntSan

您可以使用 BLOCKLIST 或函式屬性來停用 IntSan。謹慎停用 而且重構程式碼有時並不合理, 以免的效能負擔

如要進一步瞭解如何停用 IntSan,請參閱上游 Clang 說明文件 附函式 屬性BLOCKLIST 檔案 格式。BLOCKLIST 的範圍應限定為特定消毒器,例如 使用區段名稱指定目標掃毒程式,以免影響其他 消毒液

驗證

目前並未專門針對整數溢位清理的 CTS 測試。 請一律確保 CTS 測試在啟用或未啟用 IntSan 的情況下通過以進行驗證 也不會影響裝置

邊界衛生

BoundsSanitizer (BoundSan) 將檢測作業新增至二進位檔,以便插入邊界 檢查陣列存取行為。如果編譯器無法 證明存取安全無虞,以及陣列大小 以便檢查。 Android 10 會在 藍牙和轉碼器。BoundSan 是由編譯器提供,並由 這個元件會預設用於平台的各項元件

實作

BoundSan 採用 UBSan 上下限。這項緩解措施是在個別模組層級啟用。這可以 確保 Android 重要元件安全無虞,且不應停用。

強烈建議您為其他元件啟用 BoundSan。 應考慮使用特殊權限的原生程式碼或複雜的原生程式碼,並會剖析資料 不受信任的使用者輸入內容啟用 BoundSan 的相關效能負擔 取決於無法證實安全的陣列存取次數。預計有 因此平均為低負載百分比,並測試效能是否為問題所在。

在藍圖檔案中啟用 BoundSan

新增 "bounds" 即可在藍圖檔案中啟用 BoundSan 移至 misc_undefined 清理二進位檔和程式庫的屬性 模組:

    sanitize: {
       misc_undefined: ["bounds"],
       diag: {
          misc_undefined: ["bounds"],
       },
       BLOCKLIST: "modulename_BLOCKLIST.txt",
diag

diag 屬性會啟用掃毒器的診斷模式。 只在測試期間使用診斷模式。無法停用診斷模式 溢位現象,會抵銷緩解措施的安全性優勢,並具有 效能負擔較高,因此不建議用於正式環境。

封鎖清單

BLOCKLIST 屬性允許指定 BLOCKLIST 檔案,開發人員可以使用這些檔案來防止函式和來源檔案 消毒。請只在需要效能方面的考量,且目標鎖定的目標時,才使用這項資源 檔案/函式會帶來可觀的成效手動稽核這些檔案/函式 ,確保陣列存取作業安全無虞。如需其他資訊,請參閱疑難排解 詳細資料。

在 makefiles 中啟用 BoundSan

新增 "bounds" 即可在 makefile 中啟用 BoundSan 變更為二進位檔和程式庫模組的 LOCAL_SANITIZE 變數:

    LOCAL_SANITIZE := bounds
    # Optional features
    LOCAL_SANITIZE_DIAG := bounds
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt

LOCAL_SANITIZE 接受一份消毒液清單,以 逗號)。

LOCAL_SANITIZE_DIAG 會開啟診斷模式。使用診斷功能 模式。診斷模式不會針對溢位現象取消, 會降低緩解措施的安全性優勢,且更高 因此不建議用於正式環境。

LOCAL_SANITIZE_BLOCKLIST 允許指定 BLOCKLIST 檔案,方便開發人員防止程式和來源檔案 消毒。請只在需要效能方面的考量,且目標鎖定的目標時,才使用這項資源 檔案/函式會帶來可觀的成效手動稽核這些檔案/函式 ,確保陣列存取作業安全無虞。如需其他資訊,請參閱疑難排解 詳細資料。

停用 BoundSan

您可以使用 BLOCKLIST 在函式和來源檔案中停用 BoundSan,或是 函式屬性。建議保持啟用 BoundSan,因此請僅在符合以下條件時停用 BoundSan 函式或檔案會產生大量效能負擔 來源均已完成人工審查。

如要進一步瞭解如何使用 函式停用 BoundSan 屬性BLOCKLIST 檔案 格式,請參閱 Clang LLVM 說明文件。界定範圍 使用區塊名稱指定特定消毒器的封鎖清單 避免影響其他消毒液

驗證

系統沒有專門針對 BoundSan 進行 CTS 測試。相反地, 但不論是否啟用 BoundSan,這些測試都會通過,確認不會影響 裝置。

疑難排解

在啟用 BoundSan 後全面測試元件,確保先前任何 系統會處理「在範圍外未偵測到的存取權」。

界定 BoundSan 錯誤很容易就能發現,這些錯誤包括: 中止訊息:

    pid: ###, tid: ###, name: Binder:###  >>> /system/bin/foobar <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: out-of-bounds'

以診斷模式執行時,來源檔案、行號和索引 值會輸出到 logcat。根據預設 擲回通知訊息檢查「logcat」是否有任何問題 發生錯誤。

    external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'