Bug Bash Berusia 30 Tahun Akhirnya Ditemui Melalui Isu Cross-Compilation OverlayFS

Pasukan Komuniti BigGo
Bug Bash Berusia 30 Tahun Akhirnya Ditemui Melalui Isu Cross-Compilation OverlayFS

Laporan bug pelanggan rutin mengenai kegagalan OpenSSH scp telah membawa kepada penemuan bug berusia beberapa dekad dalam GNU Bash yang tidak disedari selama kira-kira 30 tahun. Penyiasatan mendedahkan pelbagai lapisan isu teknikal yang melibatkan cross-compilation, tingkah laku sistem fail, dan andaian kod warisan.

Masalah bermula apabila pelanggan melaporkan kegagalan scp selepas bertukar kepada OverlayFS pada sistem ARM 32-bit. Mesej ralat menunjukkan Bash tidak dapat menentukan direktori kerja semasa, kadang-kadang gagal dengan ralat misteri Inappropriate ioctl for device. Apa yang kelihatan seperti isu keserasian sistem fail mudah bertukar menjadi penyelidikan mendalam melalui pelbagai lapisan perisian.

Komponen Teknikal Utama Yang Terlibat:

  • Versi Bash: Dikompil silang untuk seni bina ARM
  • Sistem fail: OverlayFS pada sistem 32-bit (ciri xino tidak tersedia)
  • Sistem binaan: Linux terbenam tersuai (bukan Yocto )
  • Keadaan ralat: ENOTTY (ioctl tidak sesuai untuk peranti), pengendalian errno
  • Garis masa: Pepijat wujud selama kira-kira 30 tahun (sejak 1990an)

Cross-Compilation Mencetuskan Kod Fallback Purba

Punca utama dapat dikesan kembali kepada konfigurasi binaan Bash semasa cross-compilation. Semasa cross-compilation untuk ARM, skrip configure Bash tidak dapat menguji dengan betul sama ada fungsi getcwd() sistem memperuntukkan memori dengan betul. Sebagai langkah keselamatan, ia secara lalai menggunakan pelaksanaan getcwd() dalaman Bash sendiri - fallback yang pada asalnya direka untuk sistem Unix purba dari tahun 1990-an.

Kod fallback ini melaksanakan algoritma Unix klasik yang secara manual membina semula laluan direktori dengan memanjat pokok sistem fail, membandingkan nombor inode untuk mengenal pasti setiap komponen direktori. Pendekatan ini berfungsi dengan boleh dipercayai selama beberapa dekad pada sistem fail tradisional tetapi membuat andaian yang dipecahkan oleh sistem fail overlay moden.

Perbincangan komuniti mendedahkan isu cross-compilation ini mempengaruhi banyak sistem tertanam. Sistem binaan utama seperti Yocto mempunyai penyelesaian sementara, tetapi persekitaran binaan yang lebih kecil atau tersuai sering kekurangan pembetulan ini. Seorang pembangun menyatakan bahawa skrip configure memeriksa banyak keadaan usang yang tidak digunakan pada sistem sebenar selama beberapa dekad, mewujudkan kerumitan yang tidak perlu.

Analisis Punca Akar:

  • Punca utama: Skrip konfigurasi kompilasi silang secara lalai menetapkan GETCWD_BROKEN=yes
  • Punca kedua: Ketidakkonsistenan nombor inode OverlayFS antara readdir() dan stat()
  • Punca ketiga: Bug pengendalian errno berusia 30 tahun dalam pelaksanaan getcwd() sandaran Bash
  • Kesan platform: Secara khusus menjejaskan sistem ARM 32-bit tanpa sokongan xino

OverlayFS Memecahkan Andaian Berusia 30 Tahun

OverlayFS, yang menggabungkan pelbagai lapisan sistem fail, mengendalikan nombor inode secara berbeza daripada sistem fail tradisional. Semasa menyenaraikan kandungan direktori dengan readdir(), ia mengembalikan nombor inode mentah dari lapisan asas tanpa melakukan carian penuh. Walau bagaimanapun, semasa mendapatkan maklumat fail dengan stat(), ia menyediakan nombor inode yang stabil dan unik melalui carian penuh.

Pilihan reka bentuk ini mengutamakan prestasi untuk senarai direktori sambil mengekalkan ketepatan untuk operasi fail individu. Alat seperti find dan du berfungsi dengan betul, tetapi kod fallback purba Bash mengharapkan nombor inode dari kedua-dua operasi sepadan - andaian yang dipecahkan oleh OverlayFS.

Isu ini terutamanya mempengaruhi sistem 32-bit di mana OverlayFS tidak dapat menggunakan ciri xino untuk menyediakan nombor inode yang konsisten. Pada sistem 64-bit, ruang tambahan dalam medan inode membolehkan pengekodan data tambahan untuk mencegah konflik, tetapi sistem 32-bit kekurangan keupayaan ini.

Bug errno Berusia 30 Tahun

Mungkin yang paling mengejutkan, penyiasatan mendedahkan bug halus tetapi lama dalam pengendalian ralat Bash. Fungsi readdir() mengembalikan NULL kedua-duanya apabila mencapai penghujung direktori dan apabila menghadapi ralat. Untuk membezakan antara kes-kes ini, program mesti menetapkan errno kepada sifar sebelum memanggil readdir().

Pelaksanaan fallback getcwd() Bash terlupa langkah penting ini selama tiga dekad. Apabila readdir() tidak menemui entri direktori yang sepadan (kes biasa dengan OverlayFS), Bash salah mentafsir ini sebagai ralat dan mengembalikan apa sahaja nilai errno yang tinggal dari panggilan sistem sebelumnya. Ini menjelaskan mesej Inappropriate ioctl for device yang mengelirukan.

99% daripada masa, anda tidak perlu menetapkan errno = 0 sebelum membuat panggilan. Anda memeriksa untuk pulangan bukan sifar, dan hanya kemudian melihat errno. Tetapi KADANG-KADANG anda perlu menetapkan errno = 0, kerana dalam kes ini readdir() mengembalikan NULL pada kedua-dua ralat dan EOF.

Bug ini tidak disedari kerana kebanyakan sistem menggunakan fungsi getcwd() perpustakaan standard dan bukannya pelaksanaan fallback Bash. Hanya gabungan khusus konfigurasi cross-compilation dan OverlayFS mendedahkan kesilapan berusia beberapa dekad ini.

Penyelesaian dan Solusi:

  • Pembetulan segera: Gantikan bash_cv_getcwd_malloc=yes dalam konfigurasi pembinaan
  • Pembetulan jangka panjang: Pepijat errno dilaporkan kepada projek GNU Bash
  • Amalan industri: Sistem pembinaan Yocto sudah merangkumi penggantian yang diperlukan
  • Alternatif: Gunakan getcwd() libc moden sebagai ganti pelaksanaan sandaran Bash

Pengajaran untuk Pembangunan Perisian Moden

Pencarian bug ini menggambarkan bagaimana kod warisan boleh mewujudkan masalah yang tidak dijangka dalam persekitaran moden. Isu ini memerlukan empat faktor berasingan untuk sejajar: salah konfigurasi cross-compilation, penggunaan OverlayFS, seni bina 32-bit, dan operasi direktori khusus.

Para pembangun telah melaporkan bug pengendalian errno kepada projek GNU Bash dan melaksanakan pembetulan sistem binaan untuk mencegah isu cross-compilation. Walau bagaimanapun, penyiasatan menyerlahkan kebimbangan yang lebih luas mengenai mengekalkan andaian keserasian merentasi ekosistem perisian yang berkembang.

Sistem fail overlay moden mewakili peralihan asas dalam cara sistem penyimpanan berfungsi, berpotensi mempengaruhi aplikasi warisan lain yang membuat andaian serupa mengenai konsistensi nombor inode. Apabila kontainerisasi dan sistem fail overlay menjadi lebih berleluasa, isu keserasian serupa mungkin muncul dalam komponen perisian lain yang stabil lama.

Rujukan: Deep Down the Rabbit Hole: Bash, OverlayFS, and a 30-Year-Old Surprise