Saya telah menggunakan Systrace untuk mem-sandbox program yang tidak dipercaya baik secara interaktif maupun dalam mode otomatis. Ini memiliki ptrace()
backend berbasis yang memungkinkan penggunaannya pada sistem Linux tanpa hak khusus, serta backend yang jauh lebih cepat dan lebih kuat yang memerlukan penambalan kernel.
Dimungkinkan juga untuk membuat kotak pasir pada sistem mirip Unix menggunakan chroot(1)
, meskipun itu tidak semudah atau seaman itu. Wadah Linux dan penjara FreeBSD adalah alternatif yang lebih baik untuk chroot. Alternatif lain di Linux adalah menggunakan kerangka kerja keamanan seperti SELinux atau AppArmor, yang akan saya usulkan untuk sistem produksi.
Kami dapat membantu Anda lebih banyak jika Anda memberi tahu apa sebenarnya yang ingin Anda lakukan.
EDIT:
Systrace akan bekerja untuk kasus Anda, tetapi menurut saya sesuatu yang didasarkan pada Model Keamanan Linux seperti AppArmor atau SELinux adalah alternatif yang lebih standar, dan lebih disukai, tergantung pada distribusi Anda.
EDIT 2:
Sedangkan chroot(1)
tersedia di sebagian besar (semua?) sistem mirip Unix, ia memiliki beberapa masalah:
-
Itu bisa pecah. Jika Anda benar-benar akan mengkompilasi atau menjalankan program C yang tidak tepercaya di sistem Anda, Anda sangat rentan terhadap masalah ini. Dan jika siswa Anda seperti siswa saya, seseorang AKAN mencoba keluar dari penjara.
-
Anda harus membuat hierarki sistem file independen penuh dengan semua yang diperlukan untuk tugas Anda. Anda tidak harus memiliki kompiler di chroot, tetapi semua yang diperlukan untuk menjalankan program yang dikompilasi harus disertakan. Meskipun ada utilitas yang membantu hal ini, itu tetap tidak sepele.
-
Anda harus mempertahankan chroot. Karena independen, file chroot tidak akan diperbarui bersama dengan distribusi Anda. Anda harus membuat ulang chroot secara teratur, atau menyertakan alat pembaruan yang diperlukan di dalamnya, yang pada dasarnya mengharuskannya menjadi distribusi Linux yang lengkap. Anda juga harus menjaga data sistem dan pengguna (kata sandi, file input, dll.) disinkronkan dengan sistem host.
-
chroot()
hanya melindungi sistem file. Itu tidak mencegah program jahat membuka soket jaringan atau yang ditulis dengan buruk menyedot setiap sumber daya yang tersedia.
Masalah penggunaan sumber daya umum di antara semua alternatif. Kuota sistem file akan mencegah program mengisi disk. ulimit
yang tepat (setrlimit()
dalam C) pengaturan dapat melindungi dari penggunaan memori yang berlebihan dan bom fork apa pun, serta menghentikan CPU hogs. nice(1)
dapat menurunkan prioritas program tersebut sehingga komputer dapat digunakan untuk tugas apa pun yang dianggap lebih penting tanpa masalah.
Saya menulis ikhtisar teknik sandboxing di Linux baru-baru ini. Saya pikir pendekatan termudah Anda adalah menggunakan wadah Linux (lxc) jika Anda tidak keberatan dengan forking dan sebagainya, yang tidak terlalu penting di lingkungan ini. Anda dapat memberikan proses sistem file root hanya baca, koneksi jaringan loopback yang terisolasi, dan Anda masih dapat mematikannya dengan mudah dan menyetel batas memori, dll.
Seccomp akan menjadi sedikit sulit, karena kodenya bahkan tidak dapat mengalokasikan memori.
Selinux adalah pilihan lain, tapi menurut saya ini mungkin lebih berfungsi daripada wadah.
Anda dapat menggunakan Qemu untuk menguji tugas dengan cepat. Prosedur di bawah ini membutuhkan waktu kurang dari 5 detik pada laptop saya yang berusia 5 tahun.
Mari kita asumsikan siswa harus mengembangkan program yang menggunakan int yang tidak ditandatangani, masing-masing pada barisnya sendiri, hingga baris dengan "-1" tiba. Program kemudian harus menghitung rata-rata semua int dan menampilkan "Rata-rata:%f". Inilah cara Anda dapat menguji program yang benar-benar terisolasi:
-
Pertama, dapatkan
root.bin
dari Jslinux, kami akan menggunakannya sebagai tanah pengguna (memiliki kompiler tcc C):wget https://github.com/levskaya/jslinux-deobfuscated/raw/master/root.bin
-
Kami ingin menempatkan kiriman siswa di
root.bin
, jadi siapkan perangkat loop:sudo losetup /dev/loop0 root.bin
(Anda juga dapat menggunakan fuseext2 untuk ini, tetapi tidak terlalu stabil. Jika stabil, Anda tidak memerlukan root untuk semua ini)
-
Buat direktori kosong:
mkdir mountpoint
-
Pasang
root.bin
:sudo mount /dev/loop0 mountpoint
-
Masukkan sistem file yang terpasang:
cd mountpoint
. -
Perbaiki hak:
sudo chown -R `whoami` .
mkdir -p etc/init.d
-
vi etc/init.d
:#!/bin/sh cd /root echo READY 2>&1 > /dev/ttyS0 tcc assignment.c 2>&1 > /dev/ttyS0 ./a.out 2>&1 > /dev/ttyS0
-
chmod +x etc/init.d/rcS
-
Salin kiriman ke VM:
cp ~/student_assignment.c root/assignment.c
-
Keluar dari FS root VM:
cd ..
sudo umount mountpoint
- Sekarang gambar sudah siap, kita hanya perlu menjalankannya. Ini akan mengkompilasi dan menjalankan kiriman setelah booting.
mkfifo /tmp/guest_output
-
Buka terminal terpisah dan mulailah mendengarkan keluaran tamu:
dd if=/tmp/guest_output bs=1
-
Di terminal lain:
qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput
(Saya baru saja menggunakan kernel Ubuntu di sini, tetapi banyak kernel akan berfungsi) -
Saat keluaran tamu menunjukkan "SIAP", Anda dapat mengirimkan kunci ke VM dari perintah qemu. Misalnya, untuk menguji tugas ini, Anda dapat melakukan
(qemu) sendkey 1 (qemu) sendkey 4 (qemu) sendkey ret (qemu) sendkey 1 (qemu) sendkey 0 (qemu) sendkey ret (qemu) sendkey minus (qemu) sendkey 1 (qemu) sendkey ret
-
Sekarang
Average = 12.000000
akan muncul di pipa keluaran tamu. Jika tidak, siswa gagal. - Keluar dari qemu:
quit
Program yang lulus tes ada di sini:https://stackoverflow.com/a/14424295/309483. Cukup gunakan tcclib.h
bukannya stdio.h
.