Sandbox VM Sub-Milidetik dengan Copy-on-Write
Cara memory forking copy-on-write membuat sandbox VM yang boot di bawah 1 milidetik, dan dampaknya bagi serverless serta isolasi keamanan.

Menjalankan container Docker butuh sekitar 500 milidetik. Sebuah microVM Firecracker butuh sekitar 125 milidetik. Isolate V8 butuh sekitar 5 milidetik. Tapi generasi baru sandbox ringan, yang memakai memory forking copy-on-write, bisa menyalakan lingkungan eksekusi terisolasi dalam kurang dari 1 milidetik, sering di kisaran 50-200 mikrodetik. Itu cukup cepat untuk membuat sandbox baru untuk setiap pemanggilan fungsi.
Ini bukan sekadar peningkatan bertahap. Ini perubahan kualitatif dalam apa yang bisa dilakukan sandboxing. Ketika pembuatan sandbox memakan 500 ms, kamu membuatnya jarang lalu memakainya ulang. Ketika biayanya 50 μs, kamu membuatnya untuk setiap input yang tidak tepercaya, setiap pemanggilan plugin, dan setiap permintaan pengguna. Model keamanannya bergeser dari 'isolasi tenant' menjadi 'isolasi tiap operasi.'
Apa Sebenarnya Arti Copy-on-Write
Copy-on-write (CoW) adalah teknik sistem operasi di mana kamu membuat 'salinan' sebuah region memori tanpa benar-benar menyalin data apa pun. Baik yang asli maupun salinannya menunjuk ke halaman memori fisik yang sama, yang ditandai sebagai read-only. Keduanya tidak bisa dibedakan karena sama-sama melihat data yang identik. Penyalinan yang sesungguhnya baru terjadi ketika salah satunya mencoba menulis ke sebuah halaman. Saat itu, kernel mencegat penulisan, menyalin hanya halaman tersebut, dan membiarkan penulisan berlanjut di salinan.
System call fork() milik Unix sudah memakai teknik ini sejak 1990-an. Saat kamu melakukan fork pada sebuah proses, child mendapat salinan lengkap memori parent, tapi berkat CoW tidak ada data yang benar-benar disalin. Jika child langsung memanggil exec() (seperti biasanya), memorinya langsung diganti seluruhnya dan halaman CoW tinggal dilepas. Fork-nya hampir gratis.
// Classic fork() — copy-on-write in action
pid_t pid = fork();
// At this point:
// - Parent and child share ALL physical memory pages
// - Both have identical virtual address spaces
// - Pages are marked read-only in both
// - Zero data has been copied
if (pid == 0) {
// Child process
// Reading shared_data is free — same physical page
int value = shared_data[0];
// Writing triggers CoW — only THIS page gets copied
shared_data[0] = 42;
// Now child has its own copy of this one page
// Parent's page is unchanged
}
Dari Fork ke Sandbox
Insight CoW untuk sandbox adalah: alih-alih boot VM atau container baru dari nol, kamu pre-boot sebuah lingkungan 'template' (dengan runtime, library, dan state awal sudah dimuat), lalu melakukan fork-nya dengan CoW untuk membuat salinan instan. Setiap salinan mulai persis dari kondisi tempat template berhenti, sudah terinisialisasi penuh dan siap dieksekusi, tapi berjalan di ruang memori yang terisolasi.
Bedanya dari sisi performa sangat besar. Startup VM tradisional meliputi: memuat kernel, menginisialisasi hardware, me-mount filesystem, menjalankan sistem init, memuat kode aplikasi, dan menginisialisasi runtime. Meski sudah dioptimasi agresif (Firecracker memangkas banyak bagian ini), kamu tetap harus menjalankan pekerjaan inisialisasi yang memakan ratusan milidetik.
CoW forking melewatkan semua itu. Template sudah menyelesaikan inisialisasi, jadi fork membuat salinan yang siap pakai dalam hitungan mikrodetik. 'Biaya startup'-nya hanyalah bookkeeping kernel untuk membuat address space baru dan menggandakan entri page table, sekitar beberapa ribu operasi, terlepas dari seberapa besar memori yang dipakai template.
Di Mana Ini Mengubah Permainan
Fungsi Serverless
Cold start adalah momok di dunia serverless. AWS Lambda butuh 100-500 ms untuk cold start, dan lebih lama lagi untuk runtime berbasis JVM. Ini tidak bisa diterima untuk workload yang sensitif terhadap latensi, sehingga pengguna terpaksa menjaga instance tetap hangat (yang justru menggagalkan tujuan serverless) atau menerima latensi yang tidak bisa diprediksi.
Dengan sandbox CoW, cold start turun ke bawah satu milidetik. Setiap pemanggilan bisa menjadi 'cold start' karena cold start pada dasarnya gratis. Tidak perlu warm pool, tidak ada memori yang terbuang dari instance yang menganggur, dan tidak ada state basi antar pemanggilan. Setiap eksekusi fungsi mendapat lingkungan yang bersih dan terisolasi tanpa harus membayar biaya inisialisasi.
Sistem Plugin dan Ekstensi
Menjalankan plugin yang tidak tepercaya dengan aman adalah salah satu masalah tersulit di dunia software. Browser sudah menyelesaikannya untuk JavaScript dengan isolate V8. Tapi untuk kode arbitrer, seperti ekstensi terkompilasi, bahasa scripting, dan plugin biner, pilihan isolasinya terbatas: container (terlalu lambat untuk isolasi per-request) atau WebAssembly (ekosistem dan dukungan bahasanya terbatas).
Sandbox CoW menawarkan jalan tengah: jalankan kode arbitrer di salinan terisolasi dari lingkungan host, dengan setup dan teardown di bawah satu milidetik. Plugin melihat lingkungan OS yang lengkap (filesystem, jaringan, library), tapi perubahan yang dibuatnya terkurung. Ketika sandbox selesai, semua perubahan lenyap. Ini ideal untuk kode yang dikirim pengguna di sistem CI, lingkungan notebook, dan build tool.
Isolasi Keamanan
Saat memproses input yang tidak tepercaya, seperti mem-parsing PDF yang diunggah, merender HTML buatan pengguna, atau mengeksekusi query database, menjalankan operasi tersebut di sandbox terisolasi membatasi dampak dari exploit apa pun. Jika parser PDF punya buffer overflow, penyerang hanya mendapat kendali atas sandbox sekali pakai yang sebentar lagi dihancurkan, bukan server aplikasinya.
Pendekatan ini, yaitu isolasi proses untuk setiap operasi yang tidak tepercaya, selama ini tidak praktis dengan sandboxing tradisional karena overhead-nya melebihi waktu pemrosesan. Kalau parsing PDF makan 10 ms, menghabiskan 500 ms untuk membuat container jelas tidak masuk akal. Tapi menghabiskan 100 μs untuk membuat sandbox CoW itu murah sekali.
Detail Implementasi
Membangun sistem sandbox CoW yang praktis butuh pemecahan beberapa masalah di luar sekadar memanggil fork().
- Akuntansi memori. CoW membuat penggunaan memori jadi ambigu. Jika sebuah template memakai 1 GB dan kamu melakukan fork 100 salinan yang masing-masing memodifikasi 10 MB, penggunaan memori fisiknya sekitar 2 GB (1 GB bersama + 100 × 10 MB unik), bukan 100 GB. Kernel melacak halaman bersama dan privat, tapi untuk mendapatkan angka penggunaan per sandbox yang akurat kamu perlu mem-parsing
/proc/[pid]/smaps. - Isolasi filesystem. CoW menangani memori, tapi penulisan ke filesystem butuh isolasi tersendiri. Overlay filesystem (overlayfs) menyediakan semantik CoW untuk file: sandbox melihat filesystem template, tapi penulisan diarahkan ke lapisan terpisah. Saat sandbox selesai, overlay dibuang.
- Isolasi jaringan. Setiap sandbox perlu network namespace sendiri agar tidak saling mengganggu. Namespace Linux menyediakan ini, tapi pembuatan network namespace punya overhead yang terukur. Beberapa sistem memakai ulang pool namespace yang sudah dibuat sebelumnya.
- Batas resource. Sandbox yang mengalokasikan memori tanpa batas atau memakai CPU tanpa limit adalah celah denial-of-service. cgroups menyediakan batas resource (memori, CPU, I/O), tapi pembuatan dan penghapusan cgroup menambah overhead. Sekali lagi, pooling sangat membantu.
- Pembersihan yang deterministik. Saat sandbox selesai, semua resource-nya (memori, file descriptor, koneksi jaringan, objek IPC) harus dibersihkan dengan andal. PID namespace membantu: matikan proses init namespace tersebut dan semua turunannya ikut mati.
CoW vs Sandbox WebAssembly
WebAssembly (Wasm) adalah teknologi sandboxing ringan lain yang paling penting. Layak dibandingkan karena keduanya membuat trade-off yang fundamental berbeda.
Sandbox Wasm menjalankan kode di virtual machine yang memory-safe dengan model linear memory. Sandbox tidak bisa mengakses apa pun di luar linear memory-nya: tidak ada filesystem, tidak ada jaringan, dan tidak ada system call (kecuali disediakan secara eksplisit lewat WASI). Ini sangat aman tapi membatasi, karena kode yang sudah ada harus dikompilasi ulang ke Wasm, dan tidak semua bahasa bisa dikompilasi ke Wasm dengan baik.
Sandbox CoW menjalankan kode native di lingkungan OS yang terisolasi. Sandbox punya akses ke antarmuka OS yang lengkap (mungkin dibatasi dengan filter seccomp), bisa menjalankan binary apa pun, dan memakai library sistem yang normal. Ini kurang membatasi, tapi kurang aman karena batas isolasinya adalah model proses OS, yang punya attack surface lebih besar dibanding VM minimal milik Wasm.
Pilih Wasm jika kamu mengendalikan kode yang disandbox-kan, workload-mu terkompilasi dengan bersih ke Wasm, dan kamu butuh isolasi sekuat mungkin. Pilih sandbox CoW jika kamu perlu menjalankan binary existing yang arbitrer, workload-mu butuh kemampuan tingkat OS (filesystem, jaringan, child process), dan kamu lebih memprioritaskan kompatibilitas daripada attack surface yang minimal.
Jebakannya: Fork di Program Multithreaded
Ada jebakan yang cukup terkenal pada fork(): ia hanya menyalin thread yang memanggilnya. Jika parent punya 20 thread, child hanya dapat satu. Mutex yang sedang dipegang oleh 19 thread lainnya tetap ditandai sebagai terkunci di memori child, padahal thread pemegangnya sudah tidak ada. Child akan deadlock pertama kali mencoba mengambil salah satu mutex tersebut.
Sistem sandbox CoW mengakali ini dengan memastikan proses template hanya punya satu thread saat di-fork. Biasanya caranya: inisialisasi semuanya di template (memuat library, menyiapkan runtime, menyiapkan state awal), lalu hentikan semua thread kecuali main thread, fork, dan biarkan tiap child membuat ulang thread sesuai kebutuhan. Biaya inisialisasi dibayar sekali, dan fork menghindari bahaya threading.
Beberapa pendekatan yang lebih baru memakai userfaultfd atau custom page fault handler untuk mengimplementasikan semantik mirip CoW tanpa bergantung pada fork() sama sekali. Cara ini menghindari masalah multithreading, tapi menambah kompleksitas dan membutuhkan koordinasi di level kernel yang lebih dalam.
Yang Perlu Diperhatikan
Sandboxing sub-milidetik masih tergolong baru, tapi building block-nya sudah solid (fork, namespace, cgroups, dan overlayfs semuanya matang). Sistem yang dibangun di atasnya, untuk serverless computing, CI/CD, dan eksekusi kode yang aman, membuktikan bahwa isolasi per operasi itu praktis dalam skala besar. Seiring tools ini matang, anggapan bahwa sandboxing itu mahal akan terasa ketinggalan zaman, sama seperti anggapan bahwa garbage collection terlalu lambat untuk aplikasi real-time. Overhead-nya perlahan menghilang, dan manfaat keamanan dari 'sandbox semuanya' makin sulit diabaikan.


