2. Korumalı Alan Politikası Oluşturma

Bir yürütücüye sahip olduğunuzda, Sandboxee için bir Korumalı Alan Politikası tanımlamak isteyebilirsiniz. Aksi takdirde, Sandboxee yalnızca Varsayılan Syscall Politikası ile korunur.

Korumalı Alan Politikası'nda amaç, Sandboxee'nin yapabileceği sistem çağrılarını ve bağımsız değişkenlerin yanı sıra erişebileceği dosyaları kısıtlamaktır. Korumalı alana almayı planladığınız kodun gerektirdiği syscall'lar hakkında ayrıntılı bilgi sahibi olmanız gerekir. Sistem çağrılarını gözlemlemenin bir yolu, kodu Linux'un komut satırı araç çubuğuyla çalıştırmaktır.

Siscall'ların listesini edindikten sonra politikayı tanımlamak için PolicyBuilder'ı kullanabilirsiniz. PolicyBuilder, yaygın olarak kullanılan pek çok işleme olanak tanıyan birçok kolaylık ve yardımcı işlev sunar. Aşağıdaki liste kullanılabilir işlevlerin yalnızca küçük bir alıntısıdır:

  • İşlem başlatma için tüm syscall'ları izin verilenler listesine ekleyin:
    • AllowStaticStartup();
    • AllowDynamicStartup();
  • Açık/okuma/yazma* syscall'larını izin verilenler listesine ekleyin:
    • AllowOpen();
    • AllowRead();
    • AllowWrite();
  • Çıkış/erişim/durum ile ilgili tüm syscall'ları izin verilenler listesine ekleyin:
    • AllowExit();
    • AllowStat();
    • AllowAccess();
  • Uyku/zamanla ilgili tüm syscall'ları izin verilenler listesine ekleyin:
    • AllowTime();
    • AllowSleep();

Bu kolaylık işlevleri, ilgili tüm syscall'ları izin verilenler listesine ekler. Bu, aynı politikanın belirli syscall'ların kullanılamadığı farklı mimarilerde kullanılabilmesi avantajına sahiptir (ör. ARM64'te OPEN syscall yoktur) ancak gerekli olabilecekden daha fazla sycsall'ı etkinleştirme gibi küçük bir güvenlik riski taşır. Örneğin, AllowOpen(), Sandboxee'nin açık ve ilgili herhangi bir syscall'ı çağırmasına olanak tanır. Yalnızca belirli bir syscall'ı izin verilenler listesine eklemek istiyorsanız aynı anda birden fazla syscall'a izin vermek için AllowSyscall(); ile AllowSyscalls() kullanabilirsiniz.

Politika şu ana kadar yalnızca sistem çağrısı tanımlayıcısını kontrol eder. Politikayı daha da güçlendirmeniz gerekiyorsa ve yalnızca belirli bağımsız değişkenlerle syscall'a izin verdiğiniz bir politika tanımlamak istiyorsanız AddPolicyOnSyscall() veya AddPolicyOnSyscalls() kullanmanız gerekir. Bu işlevler yalnızca syscall kimliğini bağımsız değişken olarak almakla kalmaz, aynı zamanda Linux çekirdeğindeki bpf yardımcı makrolarını kullanan bir ham seccomp-bpf filtresi de alır. BPF hakkında daha fazla bilgi edinmek için çekirdek dokümanlarına 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ğinde bulunabilirsiniz.

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ısı, korumalı alana geçici bir dosya depolama alanı eklemek için kullanılabilir.

Özellikle kullanışlı bir işlev, ikili programların gerektirdiği kitaplıkları ve bağlayıcıyı ekleyen AddLibrariesForBinary()'dir.

Ne yazık ki izin verilenler listesine ekleme amaçlı sistem çağrısını yapmak, hâlâ biraz manuel bir iş. İkili program ihtiyaçlarınızı bildiğiniz syscall'larla bir politika oluşturun ve bunu ortak bir iş yüküyle çalıştırın. Bir ihlal tetiklenirse sistem çağrısını izin verilenler listesine ekleyin ve işlemi tekrarlayın. İzin verilenler listesine eklenmenin riskli olabileceğini düşündüğünüz bir ihlalle karşılaşırsanız ve program, hataları sorunsuz bir şekilde ele alırsa bunun yerine BlockSyscallWithErrno() kullanarak hata döndürmesini deneyebilirsiniz.

#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();
}