Mengaudit system call (syscall) pada Linux x86_64 merupakan fondasi dari agen keamanan runtime (EDR), sandbox analitik, dan alat observabilitas performa. Memilih titik intersep menentukan batas keamanan (*security boundary*), stabilitas proses, dan performa I/O aplikasi. Dua pendekatan dominan yang sering dibandingkan adalah memory-indirect patching di ruang pengguna (user-space) dan instrumentasi berbasis kernel modern menggunakan eBPF (Extended Berkeley Packet Filter).
Mekanisme Kerja: User-Space Patching vs Kernel Hooking
Syscall pada x86_64 dieksekusi melalui instruksi syscall, mentransisikan eksekusi dari Ring 3 (User Space) ke Ring 0 (Kernel Space) via handler entry_SYSCALL_64.
1. Memory-Indirect Call Patching (User-Space)
Pendekatan ini memodifikasi tabel fungsi dinamis (seperti Global Offset Table/GOT pada ELF) atau mengganti prologue fungsi pembungkus (seperti libc wrapper) di memori target secara dinamis menggunakan binary rewriting. Alur eksekusi dialihkan ke fungsi trampoline melalui dereferensi pointer tidak langsung (memory-indirect pointer).
// Contoh skematis memory-indirect hook di user-space
typedef ssize_t (*real_write_fn)(int fd, const void *buf, size_t count);
static real_write_fn original_write = NULL;
ssize_t audit_write(int fd, const void *buf, size_t count) {
// Intersep argumen sebelum syscall dieksekusi
if (fd == 1 || fd == 2) {
log_event("stdout/stderr write intercepted");
}
// Panggil fungsi asli via memory-indirect call
return original_write(fd, buf, count);
}
Kelemahan mendasar metode ini adalah instruksi syscall dapat dipanggil secara langsung (*raw inline assembly*) oleh penyerang, melewati seluruh hook yang dipasang pada GOT atau wrapper libc.
2. eBPF Tracepoints & Syscall Multiplexer (Kernel-Space)
eBPF mengeksekusi bytecode yang diverifikasi langsung di dalam kernel saat peristiwa tracepoint atau kprobe terpicu. Intersep terjadi pada subsistem raw_syscalls/sys_enter dan raw_syscalls/sys_exit.
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct sys_enter_args {
unsigned short common_type;
unsigned char common_flags;
unsigned char common_preempt_count;
int common_pid;
long id;
unsigned long args[6];
};
SEC("tracepoint/raw_syscalls/sys_enter")
int audit_sys_enter(struct sys_enter_args *ctx) {
// Audit menyeluruh: semua syscall dari thread manapun terpantau
long syscall_nr = ctx->id;
bpf_printk("Syscall dipanggil: %ld\n", syscall_nr);
return 0;
}
char _license[] SEC("license") = "GPL";
Analisis Performa dan CPU Overhead
Setiap metode memberikan profil latensi yang berbeda pada beban kerja I/O intensif:
- Memory-Indirect Call Patching: Overhead latensi per-panggilan sangat rendah (kurang dari puluhan nanodetik) karena eksekusi tetap berada di Ring 3 tanpa penambahan context switch atau transit memori kernel tambahan. Namun, jika digunakan untuk blocking atau inspection berbasis string kompleks, overhead beralih ke alokator memori user-space.
- eBPF Tracepoints: Mengharuskan transisi Ring 3 ke Ring 0 (overhead syscall standar), ditambah biaya eksekusi program eBPF dan transfer data ke user-space melalui BPF ring buffer atau perf buffer. Overhead CPU meningkat seiring tingginya frekuensi syscall per detik (misalnya ribuan panggilan
epoll_waitatauread).
Memory Safety dan Batas Keamanan
Peringatan Keamanan: Jangan pernah mengandalkan memory-indirect patching atau LD_PRELOAD untuk penegakan keamanan (*security enforcement*) yang ketat. Metode ini rentan terhadap bypass Time-of-Check to Time-of-Use (TOCTOU) di memori proses lokal dan pemanggilan register
syscalllangsung.
Dari sisi integritas proses target:
- Binary Rewriting: Menuntut pengubahan izin halaman memori (via
mprotect) menjadiPROT_READ | PROT_WRITE | PROT_EXEC. Ini melanggar prinsip W^X (Write XOR Execute) dan meningkatkan kerentanan exploitasi ROP (Return-Oriented Programming). Kesalahan kalkulasi relokasi atau rekursi hook yang tidak tertangani dapat langsung memicuSIGSEGV. - eBPF: Kode diaudit oleh kernel in-verifier sebelum dimuat. Verifier menjamin tidak ada loop tak terbatas, tidak ada akses memori di luar batas kernel (*out-of-bounds*), dan tidak ada dereferensi pointer ilegal. Kegagalan probe eBPF tidak menyebabkan *kernel panic* atau terminasi aplikasi target.
Kompleksitas Implementasi dan Portabilitas Kernel
| Faktor | Memory-Indirect Patching | eBPF (Kernel Probe) |
|---|---|---|
| Kompatibilitas Kernel | Sangat portabel lintas versi Linux; tidak bergantung pada kernel release. | Membutuhkan Linux kernel modern (4.18+ direkomendasikan, idealnya 5.4+ untuk BTF/CO-RE). |
| Hak Akses | Bisa berjalan non-root (sebatas hak akses proses user). | Membutuhkan CAP_BPF atau CAP_SYS_ADMIN saat loading program. |
| Binary Dependency | Sangat rentan terhadap variasi ABI libc, layout instruksi compiler, dan stripped binaries. | Stabil jika menggunakan CO-RE (Compile Once - Run Everywhere) via BPF Type Format (BTF). |
| Dukungan Multi-Threading | Memerlukan sinkronisasi atomik instruksi untuk menghindari race condition saat patching memori aktif. | Ditangani sepenuhnya oleh subsistem tracepoint kernel secara thread-safe. |
Biaya Operasional dan Maintainability
Penggunaan binary rewriting user-space memiliki biaya awal rendah namun biaya pemeliharaan jangka panjang yang sangat tinggi. Setiap pembaruan compiler (GCC/Clang), variasi distro Linux (musl vs glibc), atau optimasi LTO (Link-Time Optimization) berisiko merusak logika hooking patching biner.
Sebaliknya, arsitektur berbasis eBPF menggunakan libbpf dan CO-RE memusatkan pemeliharaan pada kernel interface standar. Beban operasional eBPF berada pada manajemen resource kernel (memori non-swappable untuk BPF maps) dan ketergantungan pada kernel release infrastruktur host yang homogen.
Rekomendasi Keputusan Arsitektur
- Pilih eBPF jika target sistem adalah Linux modern di cloud/server, tujuannya adalah security auditing (SIEM/EDR), deteksi anomali tanpa memodifikasi biner aplikasi, dan memerlukan audit yang tidak bisa di-bypass oleh inline assembly user-space.
- Pilih Memory-Indirect Hooking hanya jika berjalan pada lingkungan terkunci (*sandboxed container*) tanpa izin
CAP_SYS_ADMIN, membutuhkan kompatibilitas ke kernel legacy (seperti Linux 2.6/3.x), atau untuk profiling murni di lingkungan pengujian internal (*non-security*).
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!