2. Membuat Kebijakan Sandbox
Setelah memiliki eksekutor, Anda mungkin ingin menentukan Sandbox Policy untuk Sandboxee. Jika tidak, Sandboxee hanya dilindungi oleh Kebijakan Syscall Default.
Tujuan Kebijakan Sandbox adalah membatasi syscall dan argumen yang dapat dilakukan Sandboxee, serta file yang dapat diaksesnya. Anda harus memahami secara mendetail syscall yang diperlukan oleh kode yang ingin Anda batasi dengan sandbox. Salah satu cara untuk mengamati syscall adalah dengan menjalankan kode ini menggunakan alat command line, strace, dari Linux.
Setelah memiliki daftar syscall, Anda dapat menggunakan PolicyBuilder untuk menentukan kebijakan.
PolicyBuilder dilengkapi dengan banyak fungsi praktis dan fungsi bantuan yang memungkinkan banyak
operasi umum (yang sebagian besar sudah disertakan dalam
DefaultPolicyBuilder()). Daftar berikut hanya berisi sebagian kecil dari
fungsi yang tersedia:
- Mengizinkan semua syscall untuk startup proses:
AllowStaticStartup();AllowDynamicStartup();
- Mengizinkan semua syscall terbuka/baca/tulis*:
AllowOpen();AllowRead();AllowWrite();
- Mengizinkan semua syscall keluar/akses/status yang terkait:
AllowExit();AllowStat();AllowAccess();
- Mengizinkan semua syscall waktu/tidur yang terkait:
AllowTime();AllowSleep();
Fungsi praktis ini memasukkan semua syscall yang relevan ke daftar yang diizinkan. Keuntungannya, kebijakan yang sama dapat digunakan di berbagai arsitektur yang tidak memiliki syscall tertentu (misalnya, ARM64 tidak memiliki syscall OPEN), tetapi risiko keamanannya kecil karena mengaktifkan lebih banyak syscall daripada yang mungkin diperlukan. Misalnya, AllowOpen() memungkinkan Sandboxee memanggil semua syscall terbuka yang terkait. Jika hanya ingin memasukkan satu syscall tertentu ke daftar yang diizinkan, Anda dapat menggunakan AllowSyscall();
untuk mengizinkan beberapa syscall sekaligus, Anda dapat menggunakan AllowSyscalls().
Sejauh ini, kebijakan hanya memeriksa ID syscall. Jika Anda perlu memperkuat kebijakan lebih lanjut dan ingin menentukan kebijakan yang hanya mengizinkan syscall dengan argumen tertentu, Anda harus menggunakan AddPolicyOnSyscall() atau AddPolicyOnSyscalls(). Fungsi ini tidak hanya menggunakan ID syscall sebagai argumen, tetapi juga filter seccomp-bpf mentah menggunakan makro helper bpf dari kernel Linux. Baca dokumentasi
kernel
untuk mengetahui informasi selengkapnya tentang BPF. Jika Anda menulis kode BPF berulang yang menurut Anda harus memiliki wrapper kegunaan, jangan ragu untuk mengajukan permintaan fitur.
Selain fungsi terkait syscall, PolicyBuilder juga menyediakan sejumlah fungsi terkait sistem file seperti AddFile() atau AddDirectory() untuk mengikat/memasang file/direktori ke sandbox. Helper AddTmpfs() dapat digunakan untuk menambahkan penyimpanan file sementara dalam sandbox.
AddLibrariesForBinary() adalah fungsi yang sangat bermanfaat untuk menambahkan
library dan linker yang diperlukan oleh program biner.
Sayangnya, memasukkan syscall ke daftar yang diizinkan masih memerlukan sedikit pekerjaan manual. Buat kebijakan dengan syscall yang Anda ketahui dibutuhkan program biner Anda dan jalankan dengan workload umum. Jika pelanggaran dipicu, masukkan syscall ke daftar yang diizinkan dan ulangi prosesnya. Jika Anda menemukan pelanggaran yang menurut Anda berisiko untuk dimasukkan ke daftar yang diizinkan dan program menangani error dengan baik, Anda dapat mencoba membuatnya menampilkan error dengan BlockSyscallWithErrno().
Contoh berikut membuat sandbox2::PolicyBuilder secara langsung untuk menunjukkan pembatasan argumen write dan mprotect serta memblokir openat (yang akan diizinkan oleh DefaultPolicyBuilder()):
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
std::unique_ptr<sandbox2::Policy> CreatePolicy() {
return sandbox2::PolicyBuilder()
.AllowSyscall(__NR_read) // See also AllowRead()
.AllowTime() // Allow time, gettimeofday and clock_gettime
.AddPolicyOnSyscall(__NR_write, {
ARG(0), // fd is the first argument of write (argument #0)
JEQ(1, ALLOW), // allow write only on fd 1
KILL, // kill if not fd 1
})
.AddPolicyOnSyscall(__NR_mprotect, {
ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32
// macro here
JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise
// kill the process
ARG(1), // len is a 64-bit argument
JNE(0x1000, KILL), // Allow single page syscalls only, otherwise kill
// the process
ALLOW, // Allow for the syscall to proceed, if prot and
// size match
})
// Allow the openat() syscall but always return "not found".
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.BuildOrDie();
}