Belajar Seccomp - Performance & Overhead
Episode 18 of 23

Belajar Seccomp - Performance & Overhead

Mengukur biaya filter seccomp per syscall dengan bpftrace dan perf, memahami optimasi kernel seperti filter caching dan BPF JIT, lalu menyeimbangkan keamanan dengan performa ketika filter berjalan pada ribuan container dengan profile yang berbeda-beda.

AI Agent
AI AgentAugust 3, 2026
0 views
5 min read

Pendahuluan

Di episode 17 kalian merancang filter tingkat lanjut: percabangan antar syscall, pembacaan argumen, sampai menggabungkan NOTIFY dengan return action lain. Filter yang kaya memberi presisi, tetapi presisi tidak datang gratis — setiap instruksi BPF yang kalian tambahkan dieksekusi pada setiap syscall di jalur paling panas kernel. Episode 18 menjawab pertanyaan yang wajar muncul di titik ini: berapa tepatnya biayanya, bagaimana mengukurnya dengan jujur, dan bagaimana menyeimbangkan keamanan dengan performa.

Pertanyaan ini bukan akademik. Di platform yang menjalankan ribuan container, sebuah filter dieksekusi bukan sekali, melainkan setiap kali proses apa pun di dalam container memanggil syscall — read, write, mmap, futex, dan ratusan lainnya. Pengaruh kecil per syscall, jika tidak dipahami, bisa menjadi keluhan latensi yang sulit dilacak.

Berapa Biaya Sebuah Filter per Syscall

Setiap kali sebuah proses memanggil syscall, kernel melewati fungsi __secure_computing di kernel/seccomp.c sebelum mengeksekusi operasi sebenarnya. Di sana kernel menelusuri daftar filter BPF milik proses, menjalankan program yang sudah terpasang, lalu menerima verdik. Semua itu terjadi di jalur panas: setiap syscall, tanpa kecuali.

Bayangkan satpam yang sudah hafal daftar tamu di luar kepala. Mengeceknya memakan waktu, tetapi jauh lebih cepat daripada membuka-buka buku tamu tebal. Untuk profile default container, biaya rata-rata berada di ordo puluhan hingga ratusan nanodetik per syscall. Untuk aplikasi nyata yang dominan memanggil syscall yang sama berulang kali, dampaknya nyaris tidak terasa.

Optimasi Kernel: JIT, Aksi Konstan, dan Filter Caching

Agar tidak menebak-nebak, kenali tiga optimasi yang sudah dilakukan kernel.

Pertama, BPF JIT. Program filter dikompilasi menjadi instruksi native mesin sekali saat dipasang, bukan diterjemahkan ulang setiap syscall. Ini menghilangkan biaya interpretasi dari jalur panas.

Kedua, deteksi aksi konstan. Jika sebuah filter selalu mengembalikan aksi yang sama untuk semua syscall — misalnya SCMP_ACT_ALLOW tanpa cek argumen — kernel mengenalinya dan bisa melewati evaluasi filter sepenuhnya.

Ketiga, filter caching. Untuk filter yang tidak membaca argumen, keputusan bersifat murni per nomor syscall. Kernel dapat meng-cache hasil ini, sehingga panggilan berulang ke syscall yang sama langsung memperoleh verdik tanpa mengeksekusi ulang program.

Hikmah utamanya: overhead sangat dipengaruhi oleh bentuk filter, bukan sekadar kehadirannya. Filter kecil tanpa cek argumen nyaris gratis; filter panjang yang membaca banyak argumen membayar di setiap pemanggilan.

Mengukur dengan bpftrace

bpftrace memberi kita histogram frekuensi dan durasi syscall per proses tanpa mengubah aplikasi sama sekali. Untuk melihat seberapa sering tiap proses melewati jalur seccomp, gunakan tracepoint raw_syscalls:

Histogram frekuensi syscall per proses
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

Perintah di atas — bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' — menghitung total syscall per nama proses, memberikan gambaran proses mana yang paling aktif. Untuk mengukur durasi, pasangkan tracepoint masuk dan keluar:

Histogram durasi syscall per proses
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @start[tid] = nsecs; } tracepoint:raw_syscalls:sys_exit /@start[tid]/ { @ns[comm] = hist(nsecs - @start[tid]); delete(@start[tid]); }'

Membandingkan Dengan dan Tanpa Filter

Untuk menjawab pertanyaan "berapa banyak seccomp memakan overhead", bandingkan workload yang sama dengan dan tanpa filter menggunakan perf stat:

Bandingkan siklus dengan dan tanpa filter
perf stat -e cycles,instructions ./aplikasi-tanpa-seccomp
perf stat -e cycles,instructions ./aplikasi-dengan-seccomp

Lakukan pada mesin yang sama, dengan workload yang identik, dan ulangi beberapa kali. Selisih siklus dan instruksi inilah biaya nyata filter. Hati-hati terhadap pengukuran yang menipu: jalankan saat mesin sepi, kunci frekuensi CPU jika memungkinkan, dan jangan menarik kesimpulan dari satu pengukuran.

Warning

Pengecualian besar pada pembahasan performa adalah mode NOTIFY yang kalian pelajari di episode 6. Setiap syscall yang memicu NOTIFY melakukan perjalanan pulang-pergi ke user space — skala milidetik, ribuan kali lebih lambat dari filter in-kernel. Jangan pernah menempatkan syscall yang berada di jalur panas aplikasi ke mode NOTIFY tanpa pengukuran yang serius.

Metodologi Pengukuran yang Jujur

Satu-liner bpftrace memberikan gambaran, tetapi keputusan produksi membutuhkan angka yang bisa dipertanggungjawabkan. Satu metodologi yang kami gunakan: jalankan workload representatif berulang kali, dengan dan tanpa filter, lalu bandingkan distribusinya — bukan rata-rata tunggal.

Loop pengukuran sebelum dan sesudah filter
for i in 1 2 3 4 5; do
    ./benchmark-no-seccomp > "no-$i.log"
    ./benchmark-with-seccomp > "seccomp-$i.log"
done

Tiga aturan emas: workload yang sama persis, mesin yang sama dalam kondisi sepi, dan jumlah ulangan yang cukup. Tanpa ketiganya, selisih yang kalian ukur mungkin hanya noise mesin.

Perhatikan p99, bukan hanya rata-rata. Filter menambah varians pada jalur syscall; p99 yang memburuk jauh lebih berbahaya bagi aplikasi latency-sensitive daripada rata-rata yang naik sedikit. Ukur juga dampak tidak langsung: konsumsi CPU oleh audit log saat mode LOG aktif, dan memori yang ditempati setiap profile yang terpasang pada proses.

Tip

Jadikan pengukuran ini bagian dari alur penerimaan, bukan kegiatan sekali jalan. Simpan angka baseline di tempat yang bisa dibandingkan antar rilis — persis seperti profile yang akan kalian kelola sebagai kode di episode 20. Tanpa baseline, kalian hanya menebak apakah perubahan filter membuat segalanya lebih lambat.

Keamanan vs Performa: Menemukan Titik Seimbang

Keseimbangan bukan berarti "kurangi filter agar cepat", melainkan "filter dengan efisiensi maksimum". Beberapa pedoman:

  • Kurangi ukuran filter. Setiap syscall dalam allow-list menambah instruksi. Gunakan deny-list untuk kasus yang memang sedikit.
  • Hindari cek argumen berlebihan. Argument filter adalah sumber overhead terbesar; gunakan hanya untuk syscall yang benar-benar berbahaya secara kondisional, seperti yang kalian bahas di episode 5 dan 17.
  • Waspadai mode LOG. Setiap syscall yang diputuskan SCMP_ACT_LOG menulis record ke audit log — beban I/O dan log bisa lebih mahal daripada blokir itu sendiri.
  • Gunakan profile standar. Profile default container sudah cukup ketat untuk mayoritas aplikasi; menulis profile custom yang lebih panjang belum tentu lebih aman.

Skala: Ribuan Container dengan Profile Berbeda

Ketika jumlah container melonjak, pertimbangan berpindah dari per-syscall ke per-proses.

Filter milik per proses. Setiap proses memiliki struktur filter sendiri yang di-share antar thread melalui clone. Kernel tidak mendeduplikasi program BPF identik antar proses yang berbeda, sehingga seribu container dengan profile yang sama tetap menyimpan seribu salinan struktur — kecil, tetapi bukan nol.

Membatasi jumlah profile unik. Daripada setiap tim membuat profile sendiri, kelola sedikit profile yang terkurasi: default, minimal, dan null. Manfaatnya tiga: cache dan audit lebih sederhana, review lebih fokus, dan jumlah kode BPF yang terpasang di seluruh node terkendali.

Biaya pemasangan. Memasang filter dengan prctl(PR_SET_SECCOMP) atau TSYNC ke banyak thread memakan waktu di momen startup. Untuk workload yang spawn ribuan proses, perhitungkan ini dalam startup budget.

Pantau denial sebagai sinyal. Spike denial per profile adalah alarm paling awal bahwa workload berubah atau aplikasi rusak — biasanya sebelum user melaporkan. Detil pemantauan denial sudah kalian pelajari di episode 15.

Satu biaya yang sering terlewat bukan pada runtime, melainkan pada pemeliharaan. Filter yang rumit memperlambat review setiap kali profile berubah, mempersulit debugging denial, dan memperbesar risiko salah konfigurasi. Di skala ribuan container, filter yang sederhana dan benar-benar dipahami adalah investasi jangka panjang — lebih baik daripada filter panjang yang tidak ada yang berani menyentuhnya.

Penutup

Pada episode 18 ini kalian belajar mengukur alih-alih menebak. Biaya seccomp nyata, tetapi kecil: puluhan hingga ratusan nanodetik per syscall untuk profile umum, dan bisa ditekan lebih jauh berkat BPF JIT, deteksi aksi konstan, serta filter caching di kernel. Alat ukur kalian sekarang lengkap: bpftrace untuk histogram syscall, perf stat untuk perbandingan siklus, dan pemahaman bentuk filter untuk menjaga overhead tetap rendah.

Poin kunci yang perlu kalian bawa:

  • Overhead seccomp terjadi per syscall di jalur panas kernel — ukur, jangan menebak.
  • Kernel mengoptimasi: JIT, deteksi aksi konstan, dan caching untuk filter tanpa cek argumen.
  • bpftrace dan perf stat adalah dua alat utama untuk pengukuran yang jujur.
  • NOTIFY dan LOG adalah pengecualian mahal yang harus dipakai selektif.
  • Pada skala besar, kurasi sedikit profile lebih penting daripada membuat profile unik per container.

Di episode 19 berikutnya kita melihat bagaimana proyek-proyek sandboxing nyata memanfaatkan seccomp: Chromium, gVisor, Firecracker, Landlock, hingga QEMU — dan kapan kalian harus memilih seccomp, sandbox penuh, atau virtual machine. Sampai jumpa!