2. Korumalı alan politikası oluşturma
Bir yürütücünüz olduğunda, Sandboxee için bir Sandbox Politikası tanımlamak isteyebilirsiniz. Aksi takdirde, Sandboxee yalnızca Varsayılan Syscall Politikası ile korunur.
Sandbox Policy ile amaç, Sandboxee'nin yapabileceği sistem çağrılarını ve bağımsız değişkenleri, ayrıca erişebileceği dosyaları kısıtlamaktır. Koruma alanına almayı planladığınız kodun gerektirdiği sistem çağrıları hakkında ayrıntılı bilgiye sahip olmanız gerekir. Sistem çağrılarını gözlemlemenin bir yolu, kodu Linux'un komut satırı aracı strace ile çalıştırmaktır.
Sistem çağrıları listesini aldıktan sonra politikayı tanımlamak için PolicyBuilder'ı kullanabilirsiniz. PolicyBuilder, birçok yaygın işlemin yapılmasına olanak tanıyan birçok kolaylık ve yardımcı işlevle birlikte gelir. Aşağıdaki liste, kullanılabilen işlevlerin yalnızca küçük bir bölümünü içermektedir:
- İşlem başlatma için herhangi bir syscall'ı izin verilenler listesine ekleme:
AllowStaticStartup();
AllowDynamicStartup();
- Tüm open/read/write* sistem çağrılarına izin verin:
AllowOpen();
AllowRead();
AllowWrite();
- Çıkış/erişim/durumla ilgili tüm sistem çağrılarını izin verilenler listesine ekleyin:
AllowExit();
AllowStat();
AllowAccess();
- Uyku/zamanla ilgili tüm sistem çağrılarını izin verilenler listesine ekleyin:
AllowTime();
AllowSleep();
Bu kolaylık işlevleri, ilgili tüm sistem çağrılarını izin verilenler listesine ekler. Bu yöntemin avantajı, belirli sistem çağrılarının kullanılamadığı farklı mimarilerde (ör.ARM64'te OPEN sistem çağrısı yoktur) aynı politikanın kullanılabilmesidir. Ancak bu yöntemin, gerekenden daha fazla sistem çağrısının etkinleştirilmesi gibi küçük bir güvenlik riski vardır. Örneğin, AllowOpen(), Sandboxee'nin açıkla ilgili herhangi bir syscall'i çağırmasına olanak tanır. Yalnızca belirli bir syscall'ı izin verilenler listesine eklemek istiyorsanız AllowSyscall();
kullanabilirsiniz. Birden fazla syscall'ı aynı anda izin verilenler listesine eklemek için AllowSyscalls()
kullanabilirsiniz.
Şu ana kadar politika yalnızca syscall tanımlayıcısını kontrol etmektedir. Politikayı daha da güçlendirmek istiyorsanız ve yalnızca belirli bağımsız değişkenlere sahip bir sistem çağrısına izin veren bir politika tanımlamak istiyorsanız AddPolicyOnSyscall()
veya AddPolicyOnSyscalls()
kullanmanız gerekir. Bu işlevler, bağımsız değişken olarak yalnızca syscall kimliğini değil, aynı zamanda Linux çekirdeğindeki bpf yardımcı makrolarını kullanan ham bir seccomp-bpf filtresini de alır. BPF hakkında daha fazla bilgi için çekirdek belgelerine bakın. Kullanılabilirlik sarmalayıcısı olması gerektiğini düşündüğünüz tekrar eden BPF kodu yazdığınızı fark ederseniz özellik isteği gönderebilirsiniz.
PolicyBuilder, syscall ile ilgili işlevlerin yanı sıra bir dosyayı/dizini korumalı alana bağlamak için AddFile()
veya AddDirectory()
gibi dosya sistemiyle ilgili bir dizi işlev de sağlar. AddTmpfs()
yardımcı programı, sanal ortamda geçici dosya depolama alanı eklemek için kullanılabilir.
Özellikle yararlı bir işlev olan AddLibrariesForBinary()
, ikili dosya için gereken kitaplıkları ve bağlayıcıyı ekler.
İzin verilenler listesine eklenecek sistem çağrılarını belirlemek maalesef hâlâ biraz manuel çalışma gerektiriyor. İkili programınızın ihtiyaç duyduğunu bildiğiniz sistem çağrılarını içeren bir politika oluşturun ve bunu ortak bir iş yüküyle çalıştırın. İhlal tetiklenirse syscall'ı izin verilenler listesine ekleyin ve işlemi tekrarlayın. İzin verilenler listesine eklemenin riskli olabileceğini düşündüğünüz bir ihlalle karşılaşırsanız ve program hataları düzgün şekilde işliyorsa BlockSyscallWithErrno()
ile hata döndürmesini sağlayabilirsiniz.
#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();
}