UndefinedBehaviorSanitizer

UndefinedBehaviorSanitizer (UBSan) melakukan instrumentasi waktu kompilasi untuk memeriksa berbagai jenis perilaku tidak terdefinisi. Meskipun UBSan mampu mendeteksi banyak bug perilaku tidak terdefinisi, Android mendukung:

  • perataan
  • bool
  • batas
  • enum
  • float-cast-overflow
  • float-divide-by-zero
  • pembagian bilangan bulat dengan nol
  • nonnull-attribute
  • null
  • return
  • returns-nonnull-attribute
  • shift-base
  • shift-exponent
  • signed-integer-overflow
  • tidak dapat dijangkau
  • unsigned-integer-overflow
  • vla-bound

unsigned-integer-overflow, meskipun secara teknis bukan perilaku yang tidak terdefinisi, disertakan dalam sanitizer dan digunakan di banyak modul Android, termasuk komponen mediaserver, untuk menghilangkan kerentanan integer-overflow laten.

Implementasi

Di sistem build Android, Anda dapat mengaktifkan UBSan secara global atau lokal. Untuk mengaktifkan UBSan secara global, tetapkan SANITIZE_TARGET di Android.mk. Untuk mengaktifkan UBSan di tingkat per modul, tetapkan LOCAL_SANITIZE dan tentukan perilaku tidak terdefinisi yang ingin Anda cari di Android.mk. Contoh:

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)

Dan konfigurasi blueprint (Android.bp) yang setara:

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",
            ],
        },
    },

}

Pintasan UBSan

Android juga memiliki dua pintasan, integer dan default-ub, untuk mengaktifkan serangkaian pembersih secara bersamaan. Integer mengaktifkan integer-divide-by-zero, signed-integer-overflow, dan unsigned-integer-overflow. default-ub mengaktifkan pemeriksaan yang memiliki masalah performa pengompilasi minimal: bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound. Class sanitizer bilangan bulat dapat digunakan dengan SANITIZE_TARGET dan LOCAL_SANITIZE, sedangkan default-ub hanya dapat digunakan dengan SANITIZE_TARGET.

Pelaporan error yang lebih baik

Implementasi UBSan default Android memanggil fungsi tertentu saat perilaku tidak terdefinisi terjadi. Secara default, fungsi ini adalah abort. Namun, mulai Oktober 2016, UBSan di Android memiliki library runtime opsional yang memberikan pelaporan error yang lebih mendetail, termasuk jenis perilaku tidak terdefinisi yang terjadi, informasi file, dan baris kode sumber. Untuk mengaktifkan pelaporan error ini dengan pemeriksaan bilangan bulat, tambahkan kode berikut ke file Android.mk:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

Nilai LOCAL_SANITIZE mengaktifkan sanitizer selama build. LOCAL_SANITIZE_DIAG mengaktifkan mode diagnostik untuk sanitizer yang ditentukan. Anda dapat menetapkan LOCAL_SANITIZE dan LOCAL_SANITIZE_DIAG ke nilai yang berbeda, tetapi hanya pemeriksaan di LOCAL_SANITIZE yang diaktifkan. Jika pemeriksaan tidak ditentukan di LOCAL_SANITIZE, tetapi ditentukan di LOCAL_SANITIZE_DIAG, pemeriksaan tidak diaktifkan dan pesan diagnostik tidak diberikan.

Berikut adalah contoh informasi yang diberikan oleh library runtime 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')

Pembersihan luapan bilangan bulat

Overflow bilangan bulat yang tidak disengaja dapat menyebabkan kerusakan memori atau kerentanan pengungkapan informasi dalam variabel yang terkait dengan akses memori atau alokasi memori. Untuk mengatasi hal ini, kami menambahkan sanitizer overflow bilangan bulat bertanda dan tidak bertanda UndefinedBehaviorSanitizer (UBSan) Clang untuk memperkuat framework media di Android 7.0. Di Android 9, kami memperluas UBSan untuk mencakup lebih banyak komponen dan meningkatkan dukungan sistem build untuknya.

Hal ini dirancang untuk menambahkan pemeriksaan seputar operasi/instruksi aritmatika—yang mungkin meluap—untuk menghentikan proses dengan aman jika terjadi luapan. Sanitizer ini dapat memitigasi seluruh class kerentanan pengungkapan informasi dan kerusakan memori yang penyebab utamanya adalah overflow bilangan bulat, seperti kerentanan Stagefright asli.

Contoh dan sumber

Sanitasi Overflow Integer (IntSan) disediakan oleh compiler dan menambahkan instrumentasi ke dalam biner selama waktu kompilasi untuk mendeteksi overflow aritmatika. Fitur ini diaktifkan secara default di berbagai komponen di seluruh platform, misalnya /platform/external/libnl/Android.bp.

Implementasi

IntSan menggunakan sanitizer overflow bilangan bulat bertanda dan tidak bertanda UBSan. Mitigasi ini diaktifkan di tingkat per modul. Fitur ini membantu menjaga keamanan komponen penting Android dan tidak boleh dinonaktifkan.

Sebaiknya Anda mengaktifkan Sanitasi Overflow Integer untuk komponen tambahan. Target yang ideal adalah kode native yang memiliki hak istimewa atau kode native yang mem-parsing input pengguna yang tidak tepercaya. Ada sedikit overhead performa yang terkait dengan sanitizer yang bergantung pada penggunaan kode dan prevalensi operasi aritmatika. Perkirakan persentase overhead kecil dan uji jika performa menjadi masalah.

Mendukung IntSan di makefile

Untuk mengaktifkan IntSan dalam makefile, tambahkan:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE menggunakan daftar sanitizer yang dipisahkan koma, dengan integer_overflow adalah serangkaian opsi yang telah dikemas sebelumnya untuk sanitizer overflow bilangan bulat bertanda dan tidak bertanda dengan default BLOCKLIST.
  • LOCAL_SANITIZE_DIAG mengaktifkan mode diagnostik untuk sanitizer. Gunakan mode diagnostik hanya selama pengujian karena mode ini tidak akan membatalkan operasi saat terjadi overflow, sehingga sepenuhnya meniadakan keuntungan keamanan dari mitigasi. Lihat Pemecahan masalah untuk mengetahui detail tambahan.
  • LOCAL_SANITIZE_BLOCKLIST memungkinkan Anda menentukan file BLOCKLIST untuk mencegah fungsi dan file sumber dibersihkan. Lihat Pemecahan masalah untuk mengetahui detail tambahan.

Jika Anda menginginkan kontrol yang lebih terperinci, aktifkan setiap sanitizer menggunakan satu atau kedua tanda berikut:

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

Mendukung IntSan dalam file cetak biru

Untuk mengaktifkan pembersihan overflow bilangan bulat dalam file blueprint, seperti /platform/external/libnl/Android.bp, tambahkan:

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

Seperti file make, properti integer_overflow adalah serangkaian opsi yang telah dikemas sebelumnya untuk setiap sanitizer overflow bilangan bulat bertanda dan tidak bertanda dengan default BLOCKLIST.

Kumpulan properti diag mengaktifkan mode diagnostik untuk sanitizer. Gunakan mode diagnostik hanya selama pengujian. Mode diagnostik tidak membatalkan saat terjadi overflow, yang sepenuhnya meniadakan keuntungan keamanan dari mitigasi dalam build pengguna. Lihat Pemecahan masalah untuk mengetahui detail tambahan.

Properti BLOCKLIST memungkinkan spesifikasi file BLOCKLIST yang memungkinkan developer mencegah fungsi dan file sumber di-sanitize. Lihat Pemecahan masalah untuk mengetahui detail tambahan.

Untuk mengaktifkan sanitizer satu per satu, gunakan:

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

Pemecahan masalah

Jika Anda mengaktifkan pembersihan overflow bilangan bulat di komponen baru, atau mengandalkan library platform yang telah memiliki pembersihan overflow bilangan bulat, Anda mungkin mengalami beberapa masalah dengan overflow bilangan bulat yang tidak berbahaya yang menyebabkan pembatalan. Anda harus menguji komponen dengan sanitasi yang diaktifkan untuk memastikan overflow yang tidak berbahaya dapat ditampilkan.

Untuk menemukan penghentian yang disebabkan oleh pembersihan dalam build pengguna, telusuri error SIGABRT dengan pesan Abort yang menunjukkan overflow yang tertangkap oleh UBSan, seperti:

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

Stack trace harus menyertakan fungsi yang menyebabkan pembatalan, tetapi overflow yang terjadi dalam fungsi inline mungkin tidak terlihat dalam stack trace.

Untuk menentukan akar masalah dengan lebih mudah, aktifkan diagnostik di library yang memicu pembatalan dan coba reproduksi error. Dengan diagnostik diaktifkan, proses tidak akan dibatalkan dan akan terus berjalan. Tidak membatalkan akan membantu memaksimalkan jumlah overflow yang tidak berbahaya dalam jalur eksekusi tertentu tanpa harus mengompilasi ulang setelah memperbaiki setiap bug. Diagnostik menghasilkan pesan error yang mencakup nomor baris dan file sumber yang menyebabkan penghentian:

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')

Setelah operasi aritmatika yang bermasalah ditemukan, pastikan bahwa overflow tidak berbahaya dan dimaksudkan (misalnya, tidak memiliki implikasi keamanan). Anda dapat mengatasi pembatalan sanitizer dengan:

  • Memfaktorkan ulang kode untuk menghindari overflow (contoh)
  • Overflow secara eksplisit melalui fungsi __builtin_*_overflow Clang (contoh)
  • Menonaktifkan sanitasi dalam fungsi dengan menentukan atribut no_sanitize (contoh)
  • Menonaktifkan pembersihan fungsi atau file sumber melalui file BLOCKLIST (contoh)

Anda harus menggunakan solusi yang paling terperinci. Misalnya, fungsi besar dengan banyak operasi aritmatika dan satu operasi yang meluap harus difaktorkan ulang satu operasinya, bukan seluruh fungsi yang masuk dalam DAFTAR BLOKIR.

Pola umum yang dapat menyebabkan overflow tidak berbahaya meliputi:

  • Transmisi implisit saat terjadi overflow yang tidak bertanda sebelum ditransmisikan ke jenis bertanda (contoh)
  • Penghapusan daftar tertaut yang mengurangi indeks loop saat penghapusan (contoh)
  • Menetapkan jenis yang tidak bertanda ke -1, bukan menentukan nilai maks sebenarnya (contoh)
  • Loop yang mengurangi bilangan bulat tidak bertanda dalam kondisi (contoh, contoh)

Sebaiknya developer memastikan bahwa jika sanitizer mendeteksi overflow, overflow tersebut memang tidak berbahaya tanpa efek samping atau implikasi keamanan yang tidak diinginkan sebelum menonaktifkan sanitasi.

Menonaktifkan IntSan

Anda dapat menonaktifkan IntSan dengan BLOCKLIST atau atribut fungsi. Nonaktifkan dengan hemat dan hanya jika pemfaktoran ulang kode tidak masuk akal atau jika ada overhead performa yang bermasalah.

Lihat dokumentasi Clang upstream untuk mengetahui informasi selengkapnya tentang menonaktifkan IntSan dengan atribut fungsi dan pemformatan file BLOCKLIST. BLOCKLISTing harus dicakup ke sanitizer tertentu dengan menggunakan nama bagian yang menentukan target sanitizer agar tidak memengaruhi sanitizer lain.

Validasi

Saat ini, tidak ada pengujian CTS khusus untuk Sanitasi Overflow Integer. Sebagai gantinya, pastikan pengujian CTS lulus dengan atau tanpa IntSan diaktifkan untuk memverifikasi bahwa IntSan tidak memengaruhi perangkat.

Sanitasi batas

BoundsSanitizer (BoundSan) menambahkan instrumentasi ke biner untuk menyisipkan pemeriksaan batas di sekitar akses array. Pemeriksaan ini ditambahkan jika compiler tidak dapat membuktikan pada waktu kompilasi bahwa akses akan aman dan jika ukuran array akan diketahui pada waktu runtime, sehingga dapat diperiksa. Android 10 men-deploy BoundSan di Bluetooth dan codec. BoundSan disediakan oleh compiler dan diaktifkan secara default di berbagai komponen di seluruh platform.

Implementasi

BoundSan menggunakan sanitizer batas UBSan. Mitigasi ini diaktifkan di tingkat per modul. Fitur ini membantu menjaga keamanan komponen penting Android dan tidak boleh dinonaktifkan.

Sebaiknya Anda mengaktifkan BoundSan untuk komponen tambahan. Kandidat yang ideal adalah kode native istimewa atau kode native kompleks yang mem-parsing input pengguna yang tidak tepercaya. Overhead performa yang terkait dengan mengaktifkan BoundSan bergantung pada jumlah akses array yang tidak dapat terbukti aman. Anda akan mendapatkan persentase overhead kecil secara rata-rata dan uji apakah performa menjadi masalah.

Mengaktifkan BoundSan dalam file blueprint

BoundSan dapat diaktifkan dalam file blueprint dengan menambahkan "bounds" ke properti pembersihan misc_undefined untuk modul biner dan library:

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

Properti diag mengaktifkan mode diagnostik untuk sanitizer. Gunakan mode diagnostik hanya selama pengujian. Mode diagnostik tidak membatalkan saat terjadi overflow, yang meniadakan keuntungan keamanan dari mitigasi dan menimbulkan overhead performa yang lebih tinggi, sehingga tidak direkomendasikan untuk build produksi.

DAFTAR YANG TIDAK DISETUJUI

Properti BLOCKLIST memungkinkan spesifikasi file BLOCKLIST yang dapat digunakan developer untuk mencegah fungsi dan file sumber dibersihkan. Gunakan properti ini hanya jika performa menjadi masalah dan file/fungsi yang ditargetkan memberikan kontribusi yang besar. Audit file/fungsi ini secara manual untuk memastikan akses array aman. Lihat Pemecahan masalah untuk mengetahui detail tambahan.

Mengaktifkan BoundSan di makefile

BoundSan dapat diaktifkan dalam makefile dengan menambahkan "bounds" ke variabel LOCAL_SANITIZE untuk modul biner dan library:

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

LOCAL_SANITIZE menerima daftar pembersih yang dipisahkan dengan koma.

LOCAL_SANITIZE_DIAG mengaktifkan mode diagnostik. Gunakan mode diagnostik hanya selama pengujian. Mode diagnostik tidak membatalkan saat terjadi overflow, yang meniadakan keunggulan keamanan mitigasi dan menimbulkan overhead performa yang lebih tinggi, sehingga tidak direkomendasikan untuk build produksi.

LOCAL_SANITIZE_BLOCKLIST memungkinkan spesifikasi file BLOCKLIST yang memungkinkan developer mencegah fungsi dan file sumber dibersihkan. Gunakan properti ini hanya jika performa menjadi masalah dan file/fungsi yang ditargetkan memberikan kontribusi yang besar. Audit file/fungsi ini secara manual untuk memastikan akses array aman. Lihat Pemecahan masalah untuk mengetahui detail tambahan.

Menonaktifkan BoundSan

Anda dapat menonaktifkan BoundSan dalam fungsi dan file sumber dengan BLOCKLIST atau atribut fungsi. Sebaiknya tetap aktifkan BoundSan, jadi nonaktifkan hanya jika fungsi atau file menyebabkan overhead performa yang besar dan sumber telah ditinjau secara manual.

Untuk mengetahui informasi selengkapnya tentang cara menonaktifkan BoundSan dengan atribut fungsi dan pemformatan file BLOCKLIST, lihat dokumentasi Clang LLVM. Cakupan BLOCKLIST ke sanitizer tertentu dengan menggunakan nama bagian yang menentukan target sanitizer untuk menghindari dampak pada sanitizer lain.

Validasi

Tidak ada pengujian CTS khusus untuk BoundSan. Sebagai gantinya, pastikan pengujian CTS lulus dengan atau tanpa BoundSan diaktifkan untuk memverifikasi bahwa BoundSan tidak memengaruhi perangkat.

Pemecahan masalah

Uji komponen secara menyeluruh setelah mengaktifkan BoundSan untuk memastikan bahwa akses di luar batas yang sebelumnya tidak terdeteksi telah ditangani.

Error BoundSan dapat diidentifikasi dengan mudah karena mencakup pesan pembatalan tombstone berikut:

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

Saat berjalan dalam mode diagnostik, file sumber, nomor baris, dan nilai indeks dicetak ke logcat. Secara default, mode ini tidak memunculkan pesan pembatalan. Tinjau logcat untuk memeriksa error.

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