- Ladybird memang sudah bisa menangani konten web normal sampai batas tertentu, tetapi ketika fuzzer DOM Domato dari Google Project Zero dijalankan, edge case tersembunyi di engine browser cepat terungkap
- Dari input abnormal yang secara realistis mungkin terjadi—seperti DOM yang dibuat dengan JavaScript untuk melewati aturan parser, dokumen tanpa window, dan referensi SVG siklik—ditemukan dan diperbaiki 5 bug nyata
- Prasangka implisit di dalam implementasi, seperti asumsi bahwa `` memiliki ancestor table, asumsi bahwa dokumen
DOMParser memiliki window, dan kesalahan penelusuran sibling pada Element.before(), berujung pada crash atau infinite loop
- Masalah akses
contentWindow pada iframe yang sudah dihapus bukan hanya cacat khusus Ladybird, tetapi juga berkaitan dengan asumsi browsing context dalam spesifikasi HTML, sehingga berlanjut menjadi isu WHATWG HTML
- Fuzzer seperti Domato mengekspos masalah keamanan dan stabilitas yang sulit ditangkap hanya dengan pengujian halaman web normal; tantangan Ladybird berikutnya adalah menstabilkannya hingga mampu menahan fuzzing berkelanjutan lalu menjalankannya secara otomatis
Stress test Ladybird dengan Domato
- Ladybird bisa menangani konten web yang tersusun dengan baik sampai batas tertentu, tetapi pengujian ini melempar input aneh dengan tool riset keamanan untuk melihat masalah apa yang muncul
- Tool yang digunakan adalah fuzzer DOM Domato dari Google Project Zero
- Domato menghasilkan halaman web acak berisi campuran HTML, CSS, JavaScript yang kebanyakan valid tetapi aneh
- Halaman yang dihasilkan dimuat ke debug build Ladybird dan perilakunya diamati
- Karena README Domato menonjolkan banyak bug yang ditemukan di browser-browser besar, tool ini dinilai juga bisa menemukan cacat bermakna di Ladybird
Dereferensi pointer null ketika berada di dalam
- Masalah pertama ditemukan dalam waktu kurang dari 1 detik, dan output Domato berukuran 562KiB bisa diperkecil menjadi bentuk berikut
let mfrac = document.createElement("mfrac");
mfrac.appendChild(document.createElement("th"));
document.body.appendChild(mfrac);
- Pada build Ladybird dengan UBSAN diaktifkan, pemanggilan
table_containing_cell di HTMLTableCellElement.cpp menyebabkan dereferensi pointer null
- Penyebabnya adalah implementasi
dan di Ladybird mengasumsikan bahwa selalu ada `` di atasnya dalam pohon DOM
- Parser HTML tidak mengizinkan markup seperti ``
- Browser yang mengikuti spesifikasi, ketika memuat markup di atas, membuat satu `` yang isinya kosong
- Namun jika node dibuat langsung lewat JavaScript DOM API, sebagian aturan parser bisa dilewati sehingga
dapat dimasukkan ke dalam
- Kode yang bermasalah digunakan untuk mengimplementasikan perilaku lama ketika
dan menerapkan CSS border serta padding bukan hanya ke box table, tetapi juga ke tiap cell
- Perbaikannya dilakukan dengan menghapus asumsi bahwa
dan selalu memiliki ancestor ``
- Menggunakan
first_ancestor_of_type() alih-alih table_containing_cell(*this)
- Jika tidak ada ancestor table, langsung return
- Commit perbaikannya ada di sini
Meng-assign event handler `` pada dokumen tanpa window
- Masalah kedua juga ditemukan dalam waktu kurang dari 1 detik, dan output Domato berukuran 472KiB diringkas menjadi kode berikut
var parser = new DOMParser();
var doc = parser.parseFromString("", "text/html");
var body = doc.createElement("body");
body.onblur = null;
- Ladybird berhenti karena kegagalan validasi
GCPtr
- Intinya ada pada perilaku khusus atribut event handler
onfoo milik ``
- Demi kompatibilitas dengan konten web lama, assignment
document.body.onfoo harus diteruskan ke window.onfoo
- Namun dokumen yang dibuat dengan
DOMParser tidak memiliki objek window
- Model objek internal Ladybird keliru tersusun dengan asumsi bahwa semua document selalu memiliki window
- Setelah diperbaiki,
Document::window() mengembalikan nilai nullable, dan null ditangani di berbagai tempat
- Jika
document.body.onblur di-assign pada dokumen tanpa window, tidak terjadi apa-apa, sama seperti browser lain
Referensi siklik pada SVG ``
- Masalah ketiga adalah rekursi tak hingga yang terjadi ketika gradient SVG mereferensikan dirinya sendiri
- SVG harus mendukung baik inline SVG di dalam HTML maupun format gambar eksternal, dan gradient dapat mereferensikan gradient lain untuk mewarisi warna
- Implementasi Ladybird tidak mempertimbangkan kasus ketika gradient mereferensikan dirinya sendiri, sehingga terus berputar saat mengikuti rantai referensi
- Jika hanya mencegah kasus referensi ke diri sendiri secara langsung, referensi siklik bertahap tetap tidak tertangani
- Penanganan yang benar adalah melacak semua gradient yang sudah dikunjungi, lalu menghentikan penelusuran rantai ketika bertemu lagi dengan gradient yang sudah dikunjungi
- Firefox menampilkan keluhan di developer console untuk jenis gradient seperti ini
Akses properti window dari iframe yang sudah dihapus dan bug spesifikasi HTML
- Masalah keempat terjadi saat memanggil
getSelection() dari contentWindow yang sebelumnya disimpan setelah iframe dihapus
window.onload = function() {
let iframe = document.querySelector("iframe")
let iframeWindow = iframe.contentWindow;
iframe.remove();
iframeWindow.getSelection();
}
- Ladybird mengeluarkan runtime error binding referensi pointer null terhadap
BrowsingContext di WindowProxy.cpp
- Ketika iframe dihapus dari DOM, content document-nya terlepas dari browsing context miliknya
- Saat mengambil atau mengatur properti objek window, algoritme spesifikasi HTML
"check if an access between two browsing contexts should be reported" dijalankan
- Algoritme ini memeriksa browsing context dari window yang mengakses dan window yang menjadi target akses
- Spesifikasi secara keliru mengasumsikan bahwa pada saat akses properti, kedua window memiliki browsing context yang terhubung
- Sebuah isu untuk spesifikasi HTML dibuka, dan Ladybird untuk sementara menambahkan pemeriksaan null
- Jika menemukan bug spesifikasi saat mengerjakan Ladybird, kita bisa memperbaiki spesifikasi untuk semua orang melalui laporan bug atau usulan perbaikan
Infinite loop pada Element.before()
- Masalah kelima berupa loading halaman yang tidak pernah selesai dan penggunaan CPU 100%
two.before(one);
- Penyebabnya adalah kesalahan pada logika implementasi
before() yang mencari sibling sebelumnya pertama dari `` yang tidak termasuk dalam argumen
- Loop lama selalu mengambil ulang
node->previous_sibling() setiap iterasi
while (auto previous_sibling = node->previous_sibling()) {
// check if previous_sibling is one of the arguments
}
- Seharusnya loop bergerak mengikuti rantai sibling dengan
previous_sibling->previous_sibling()
for (auto sibling = node->previous_sibling(); sibling; sibling = sibling->previous_sibling()) {
// check if previous_sibling is one of the arguments
}
Hasil fuzzing dan langkah berikutnya
- Sesi ini menemukan 5 bug nyata; salah satunya adalah bug spesifikasi HTML, dan semuanya telah diperbaiki
- Terungkap bahwa Ladybird bisa sangat cepat tumbang ketika bertemu input aneh dan tak terduga
- Fuzzer seperti Domato adalah sumber daya berguna bagi siapa pun yang ingin membuat software lebih tangguh
- Langkah berikutnya adalah menstabilkan Ladybird sampai level yang mampu menahan input fuzzing berkelanjutan
- Setelah cukup stabil, rencananya tool ini akan dijalankan otomatis di suatu tempat di cloud untuk menemukan lebih banyak masalah
1 komentar
Komentar Hacker News
Ini menunjukkan dengan baik mengapa beberapa implementasi independen dari sebuah spesifikasi itu bernilai.
Dari satu tulisan ini saja sudah ditemukan satu celah dalam spesifikasi, dan rasanya masih ada lagi atau akan muncul lagi ke depannya.
Untuk kesehatan jangka panjang platform web, beberapa implementasi independen itu penting, jadi kami juga sedang berusaha mengambil peran itu.
Misalnya, rasanya mirip seperti saya men-tweet “terong adalah sayuran favorit saya”, lalu seseorang mengoreksi “sebenarnya itu buah”, dan kemudian saya berkata “nilai Twitter terbukti.”
Bukan berarti pekerjaan ini sendiri atau keberadaan beberapa implementasi spesifikasi tidak bernilai, tetapi menurut saya implikasi itu belum terbukti hanya dari contoh spesifik ini.
Saya senang proyek ini terus menunjukkan bahwa tim kecil pun bisa membuat hal yang luar biasa.
Di dalam perusahaan dengan banyak pemangku kepentingan, rasanya akan jauh lebih sulit menyelesaikan hal seperti ini.
Kalau ini proyek hobi, kapan saja bisa kembali dan membangun ulang, tetapi sulit menghilangkan perasaan bahwa sebagian dari hal-hal ini seharusnya sudah masuk ke arsitektur sejak awal.
Mereka sudah mengimplementasikan SVG? Perkembangannya jauh lebih cepat dari yang saya kira, jadi saya mengikutinya dengan penuh minat.
Khususnya animasi adalah bagian besar yang masih hilang.
Untuk isu #3, sepertinya bagus juga memberi batas kedalaman maksimum pada gradien yang menunjuk ke gradien lain.
Itu bisa menjadi pertahanan berlapis untuk mengantisipasi kesalahan atau keterbatasan logika “apakah referensi ini pernah saya lihat sebelumnya”.
Saya tidak begitu paham gradien SVG, dan mungkin saja ada alasan sah untuk rantai referensi sampai 1000 tingkat, tetapi kalau melihat hal seperti itu di lingkungan nyata, menurut saya kemungkinan besar itu serangan atau input fuzzer.
Komentar ini sedang ditulis di Ladybird.
Sekarang Hacker News berjalan di Ladybird.
Saya memakai Ladybird saat menjelajahi situs seperti Hacker News atau OSnews selama beberapa menit sehari.
Lambat dan rapuh, tetapi berfungsi. Mengingat proyek ini masih sangat muda dan benar-benar ditulis dari nol, itu saja sudah mengesankan.
Saya sangat menantikan Ladybird menjadi lebih matang.
Menarik, tetapi saya terganggu karena hampir semua developer berhenti seperti yang terlihat pada isu #1: “Ketemu! Sudah saya commit perbaikannya, selesai!”
Seharusnya tidak begitu; mereka harus memahami persis apa yang salah. Misalnya, kalau masalahnya adalah asumsi bahwa “parent pasti ada”, maka harus dicari kesalahan sejenis di seluruh codebase.
Gunakan kreativitas untuk mencari di mana lagi hal yang sama bisa terjadi. Tidak mungkin hanya ada di satu tempat.
Software modern menjadi mimpi buruk penuh bug yang sulit dipercaya sebagian besar karena batasan kapitalistis, tetapi kita tetap bisa melakukan yang lebih baik.
Saya penasaran apakah Ladybird akan hadir di Web Engines Hackfest tahun ini.
Sedikit berbeda, tetapi saya penasaran apa kabar video hacking di YouTube.
Dulu saya menunggu video baru, tetapi rasanya sudah cukup lama tidak melihatnya.
Saya masih mengunggah video update bulanan, tetapi sudah beberapa bulan berlalu sejak video hacking terakhir.
Meski begitu, saya tetap mengerjakan Ladybird setiap hari, dan berkat dukungan sponsor yang murah hati dari Shopify dan pihak lain tahun lalu, sekarang saya juga mengelola dua engineer full-time.