Konsep Naked Linux Boot dan Vektor Serangan

Naked Linux boot merujuk pada arsitektur sistem operasi di mana kernel Linux melakukan boot langsung ke binary statis tunggal tanpa userland standar seperti systemd, SysVinit, glibc dinamis, utilitas coreutils, atau shell interaktif. Pola ini umum digunakan pada arsitektur appliance berbasis microVM (Firecracker/Cloud-Hypervisor), node enklaf komputasi rahasia (confidential computing), dan edge embedded appliance.

Sistem Linux konvensional memiliki attack surface luas akibat daemon latar belakang, soket IPC yang tidak diproteksi, serta binary suid. Namun, arsitektur naked Linux boot tetap menghadapi risiko spesifik:

  • Modifikasi Root Filesystem: Jika root filesystem bersifat read-write atau tidak divalidasi integritasnya secara kriptografis, attacker dengan persistensi lokal dapat memanipulasi binary executable.
  • Kebocoran Secret Memory: Kredensial, private key TLS, atau token dekripsi yang disimpan pada filesystem sementara rentan terkena swap paging atau core dump.
  • Privilege Escalation via Kernel Capabilities: Binary init yang berjalan sebagai PID 1 secara default mempertahankan seluruh Linux capabilities jika tidak didrop secara eksplisit.

Verifikasi Integritas Rootfs Menggunakan dm-verity

Untuk memastikan bahwa userland minimal tidak dimanipulasi sebelum atau selama runtime, blok storage diverifikasi menggunakan modul kernel dm-verity. Modul ini menyediakan transparent integrity checking tingkat blok menggunakan hash tree.

Generate hash tree dari image rootfs yang telah dibuat:

# 1. Format image menggunakan veritysetup
veritysetup format /dev/loop0 /dev/loop1 > verity_meta.txt

# 2. Contoh output metadata
# UUID:            e68b3f62-7935-42b7-84d4-28b3d027f82b
# Hash type:       1
# Data blocks:     262144
# Data block size: 4096
# Hash block size: 4096
# Hash algorithm:  sha256
# Root hash:       a8f4c2810a99e4b60e451b6978438db0366bcbe84d36ef55b23d9b0dc850f837

Root hash tersebut kemudian dipassing ke kernel command line atau disematkan langsung dalam built-in kernel configuration:

root=/dev/dm-0 dm-mod.create="verity-root,,,ro,0 524288 verity 1 /dev/vda /dev/vdb 4096 4096 65536 1 sha256 a8f4c2810a99e4b60e451b6978438db0366bcbe84d36ef55b23d9b0dc850f837 0" ro

Kernel akan langsung memicu I/O error jika ada blok filesystem /dev/vda yang tidak cocok dengan hash tree di /dev/vdb saat proses pembacaan berlangsung.

Implementasi Init Statis dalam Bahasa C

Penggunaan shell script sebagai init (/bin/sh) membuka celah eksekusi parsing perintah dan ketergantungan environment. Implementasi init berbasis C yang dikompilasi statis dengan musl-libc memberikan kontrol granular atas mount flags dan dropping privileges.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/capability.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

static void mount_essential(void) {
    // Mount proc dan sysfs dengan flag restriktif
    if (mount("proc", "/proc", "proc", MS_NODEV | MS_NOEXEC | MS_NOSUID, NULL) != 0)
        _exit(1);
    if (mount("sysfs", "/sys", "sysfs", MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RDONLY, NULL) != 0)
        _exit(2);

    // Mount direktori ephemeral untuk secret di RAM
    if (mount("tmpfs", "/run/secrets", "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, "size=4M,mode=0700") != 0)
        _exit(3);
}

static void drop_capabilities(void) {
    // Blok perolehan privilege baru melalui execve
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)
        _exit(4);

    // Lepaskan semua capabilities kecuali yang dibutuhkan (contoh: CAP_NET_BIND_SERVICE)
    struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
    struct __user_cap_data_struct data[2] = {0};
    
    // Kosongkan permitted, effective, dan inheritable
    if (capset(&hdr, data) != 0)
        _exit(5);
}

int main(void) {
    // Cegah swapping seluruh memory address space process init
    if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0)
        _exit(6);

    mount_essential();
    drop_capabilities();

    // Payload aplikasi atau loop eksekusi utama berjalan di sini
    while (1) {
        sleep(3600);
    }

    return 0;
}

Kompilasi binary secara statis tanpa dynamic linker dependencies:

musl-gcc -static -Wall -Wextra -O2 -fstack-protector-strong -D_FORTIFY_SOURCE=2 init.c -o /build/init

Isolasi dan Penanganan Secret Ephemeral

Secret seperti TLS private key atau API token tidak boleh ditulis ke persistent disk. Pola yang benar adalah memuat secret dari transport aman (seperti confidential VM attestation channel atau memory ballooning) langsung ke filesystem berbasis RAM.

Konfigurasi Mount tmpfs yang Aman

Mount point untuk secret harus selalu membatasi eksekusi file dan manipulasi bit SUID:

mount -t tmpfs -o rw,nosuid,nodev,noexec,size=2M,mode=0700 tmpfs /run/secrets
  • nosuid: Mematikan efek bit set-user-identifier atau set-group-identifier.
  • nodev: Mencegah pembuatan block/character special devices via mknod.
  • noexec: Mencegah eksekusi biner langsung dari direktori ini.
  • size=2M: Membatasi potensi denial-of-service via resource exhaustion memory.

Mencegah Disk Spillage via Paging dan Dump

Pastikan swap memory dinonaktifkan di tingkat kernel config (CONFIG_SWAP=n). Nonaktifkan core dump secara global untuk mencegah secret tereksploitasi pasca-crash:

echo 0 > /proc/sys/fs/suid_dumpable
echo "" > /proc/sys/kernel/core_pattern

Verifikasi Runtime Isolasi Kredensial

Verifikasi status proteksi proses dan filesystem menggunakan antarmuka /proc:

# 1. Pastikan mountpoint /run/secrets memiliki flag yang tepat
grep '/run/secrets' /proc/mounts
# Output yang diharapkan: tmpfs /run/secrets tmpfs rw,nosuid,nodev,noexec,relatime,size=2048k,mode=700 0 0

# 2. Verifikasi status Linux Capabilities pada PID 1
grep '^Cap' /proc/1/status
# Output yang diharapkan (seluruh capability telah di-drop):
# CapInh: 0000000000000000
# CapPrm: 0000000000000000
# CapEff: 0000000000000000
# CapBnd: 0000000000000000
# CapAmb: 0000000000000000

# 3. Verifikasi flag NoNewPrivs
grep 'NoNewPrivs' /proc/1/status
# Output: NoNewPrivs: 1

Trade-off: Maintainability vs Attack Surface

Mereduksi sistem operasi ke binary tunggal menghapus celah serangan secara signifikan, namun membawa kompromi operasional:

AspekNaked Linux BootDistribusi Standar (systemd)
Attack SurfaceSangat Rendah (tidak ada shell, paket ekstra, atau open listener).Tinggi (banyak background service, shared libraries).
Debugging & ObservabilitySulit (membutuhkan serial console, dmesg, atau logging via network socket kustom).Mudah (tersedia journalctl, SSH, dynamic tracing, GDB).
Update ManagementImage-based (replace kernel + rootfs secara atomik).Package-based (menggunakan apt/dnf/apk).
Cold Boot LatencySangat Cepat (< 50ms pada microVM).Sedang hingga Lambat (1 - 5 detik).

Naked Linux boot ideal untuk workload immutable yang tidak membutuhkan intervensi manusia saat runtime. Untuk workload yang masih membutuhkan debugging mendalam, siapkan build alternatif dengan Busybox yang hanya diaktifkan di development environment.