Laporan bug rutin dari pelanggan tentang kegagalan OpenSSH scp telah mengarah pada penemuan bug berusia puluhan tahun di GNU Bash yang tidak terdeteksi selama kurang lebih 30 tahun. Investigasi ini mengungkap berbagai lapisan masalah teknis yang melibatkan cross-compilation, perilaku filesystem, dan asumsi kode lama.
Masalah dimulai ketika seorang pelanggan melaporkan kegagalan scp setelah beralih ke OverlayFS pada sistem ARM 32-bit. Pesan error menunjukkan Bash tidak dapat menentukan direktori kerja saat ini, terkadang gagal dengan error yang membingungkan Inappropriate ioctl for device. Yang tampak seperti masalah kompatibilitas filesystem sederhana berubah menjadi penyelidikan mendalam melalui berbagai lapisan perangkat lunak.
Komponen Teknis Utama yang Terlibat:
- Versi Bash: Cross-compiled untuk arsitektur ARM
- Filesystem: OverlayFS pada sistem 32-bit (fitur xino tidak tersedia)
- Build system: Custom embedded Linux (bukan Yocto)
- Kondisi error: ENOTTY (Inappropriate ioctl for device), penanganan errno
- Timeline: Bug telah ada selama kurang lebih 30 tahun (sejak tahun 1990-an)
Cross-Compilation Memicu Kode Fallback Kuno
Akar penyebab masalah ini dapat ditelusuri kembali ke konfigurasi build Bash selama cross-compilation. Ketika melakukan cross-compilation untuk ARM, script configure Bash tidak dapat menguji dengan benar apakah fungsi getcwd() sistem mengalokasikan memori dengan benar. Sebagai langkah pengamanan, sistem default menggunakan implementasi getcwd() internal Bash sendiri - sebuah fallback yang awalnya dirancang untuk sistem Unix kuno dari tahun 1990-an.
Kode fallback ini mengimplementasikan algoritma Unix klasik yang secara manual merekonstruksi jalur direktori dengan naik ke atas pohon filesystem, membandingkan nomor inode untuk mengidentifikasi setiap komponen direktori. Pendekatan ini bekerja dengan andal selama puluhan tahun pada filesystem tradisional tetapi membuat asumsi yang dilanggar oleh filesystem overlay modern.
Diskusi komunitas mengungkapkan bahwa masalah cross-compilation ini mempengaruhi banyak sistem embedded. Sistem build utama seperti Yocto memiliki solusi sementara, tetapi lingkungan build yang lebih kecil atau kustom sering kali tidak memiliki perbaikan ini. Seorang developer mencatat bahwa script configure memeriksa banyak kondisi usang yang tidak berlaku untuk sistem nyata selama puluhan tahun, menciptakan kompleksitas yang tidak perlu.
Analisis Akar Masalah:
- Penyebab utama: Skrip konfigurasi cross-compilation secara default mengatur GETCWD_BROKEN=yes
- Penyebab sekunder: Inkonsistensi nomor inode OverlayFS antara readdir() dan stat()
- Penyebab tersier: Bug penanganan errno berusia 30 tahun dalam implementasi getcwd() fallback Bash
- Dampak platform: Secara khusus mempengaruhi sistem ARM 32-bit tanpa dukungan xino
OverlayFS Merusak Asumsi Berusia 30 Tahun
OverlayFS, yang menggabungkan beberapa lapisan filesystem, menangani nomor inode secara berbeda dari filesystem tradisional. Ketika mendaftar konten direktori dengan readdir(), sistem mengembalikan nomor inode mentah dari lapisan yang mendasari tanpa melakukan pencarian penuh. Namun, ketika mendapatkan informasi file dengan stat(), sistem menyediakan nomor inode yang stabil dan unik melalui pencarian penuh.
Pilihan desain ini memprioritaskan performa untuk daftar direktori sambil mempertahankan akurasi untuk operasi file individual. Tools seperti find dan du bekerja dengan benar, tetapi kode fallback kuno Bash mengharapkan nomor inode dari kedua operasi cocok - sebuah asumsi yang dilanggar oleh OverlayFS.
Masalah ini terutama mempengaruhi sistem 32-bit di mana OverlayFS tidak dapat menggunakan fitur xino untuk menyediakan nomor inode yang konsisten. Pada sistem 64-bit, ruang ekstra dalam field inode memungkinkan encoding data tambahan untuk mencegah konflik, tetapi sistem 32-bit tidak memiliki kemampuan ini.
Bug errno Berusia 30 Tahun
Mungkin yang paling mengejutkan, investigasi ini mengungkap bug yang halus namun sudah berlangsung lama dalam penanganan error Bash. Fungsi readdir() mengembalikan NULL baik ketika mencapai akhir direktori maupun ketika mengalami error. Untuk membedakan antara kedua kasus ini, program harus mengatur errno ke nol sebelum memanggil readdir().
Implementasi fallback getcwd() Bash melupakan langkah penting ini selama tiga dekade. Ketika readdir() tidak menemukan entri direktori yang cocok (kasus normal dengan OverlayFS), Bash salah menginterpretasikan ini sebagai error dan mengembalikan nilai errno apa pun yang tersisa dari panggilan sistem sebelumnya. Ini menjelaskan pesan Inappropriate ioctl for device yang menyesatkan.
99% dari waktu, Anda tidak perlu mengatur errno = 0 sebelum melakukan panggilan. Anda memeriksa return yang tidak nol, dan baru kemudian melihat errno. Tetapi TERKADANG Anda perlu mengatur errno = 0, karena dalam hal ini readdir() mengembalikan NULL baik pada error maupun EOF.
Bug ini tidak terdeteksi karena sebagian besar sistem menggunakan fungsi getcwd() dari standard library daripada implementasi fallback Bash. Hanya kombinasi spesifik dari konfigurasi cross-compilation dan OverlayFS yang mengekspos kelalaian berusia puluhan tahun ini.
Solusi dan Penyelesaian:
- Perbaikan langsung: Timpa bash_cv_getcwd_malloc=yes dalam konfigurasi build
- Perbaikan jangka panjang: Bug errno dilaporkan ke proyek GNU Bash
- Praktik industri: Sistem build Yocto sudah menyertakan override yang diperlukan
- Alternatif: Gunakan getcwd() libc modern alih-alih implementasi fallback Bash
Pelajaran untuk Pengembangan Perangkat Lunak Modern
Pencarian bug ini mengilustrasikan bagaimana kode lama dapat menciptakan masalah yang tidak terduga dalam lingkungan modern. Masalah ini memerlukan empat faktor terpisah untuk selaras: miskonfigurasi cross-compilation, deployment OverlayFS, arsitektur 32-bit, dan operasi direktori spesifik.
Para developer telah melaporkan bug penanganan errno ke proyek GNU Bash dan mengimplementasikan perbaikan sistem build untuk mencegah masalah cross-compilation. Namun, investigasi ini menyoroti kekhawatiran yang lebih luas tentang mempertahankan asumsi kompatibilitas di seluruh ekosistem perangkat lunak yang berkembang.
Filesystem overlay modern mewakili pergeseran fundamental dalam cara kerja sistem penyimpanan, berpotensi mempengaruhi aplikasi lama lainnya yang membuat asumsi serupa tentang konsistensi nomor inode. Seiring containerization dan filesystem overlay menjadi lebih umum, masalah kompatibilitas serupa mungkin muncul di komponen perangkat lunak lain yang sudah stabil lama.
Referensi: Deep Down the Rabbit Hole: Bash, OverlayFS, and a 30-Year-Old Surprise