Sürecin Linux'ta yeni dosya tanımlayıcı açmasını engelleyin, ancak soketler aracılığıyla dosya tanımlayıcılarının alınmasına izin verin


9

Şu anda bir soket çifti, çatal ayarlar ve daha sonra iletişim kurmak için bu soket çifti kullanan bir üst işlem var bir proje üzerinde çalışıyorum. Çocuk, bir dosyayı (veya başka bir dosya tanımlayıcı tabanlı kaynağı) açmak istiyorsa her zaman üst fdöğeye gitmeli, kaynağı istemeli ve soket çifti aracılığıyla gönderilmelidir. Ayrıca çocuğun tek başına herhangi bir dosya tanıtıcısını açmasını önlemek istiyorum.

setrlimitÇocuğun yeni dosya tanımlayıcıları açmasını başarıyla engellediğini tökezledim , ancak ilk soket bağlantısı üzerinden gönderilen dosya tanımlayıcılarını geçersiz kılıyor gibi görünüyor. Linux'ta tek bir işlemin herhangi bir dosyayı açmasına, dosya tanımlayıcısını diğer işlemlere göndermesine ve bu işlemlerin herhangi bir dosya tanımlayıcısını kendileri açmasına izin vermeden kullanmasına izin veren herhangi bir yöntem var mı?

Çataldan sonra uygulanabildiği ve tüm dosya tanımlayıcıları (yalnızca dosyalar değil, aynı zamanda soketler, soket çiftleri vb.) İçin geçerli olduğu sürece herhangi bir çekirdek yapılandırması, sistem çağrısı vb.


1
İlginizi çekebilir seccomp.
user253751

Yanıtlar:


6

Burada tam olarak seccomp kullanım örneği var .

Seccomp kullanarak, sistem çağrılarını farklı şekillerde filtreleyebilirsiniz. Ne bu durumda ne istiyorum hemen sonra olan fork()bir yüklemeye, seccompkullanımını izin vermez filtresi open(2), openat(2), socket(2)(ve daha fazla). Bunu yapmak için aşağıdakileri yapabilirsiniz:

  1. İlk olarak, seccomp_init(3)varsayılan davranışı ile bir seccomp içeriği oluşturun SCMP_ACT_ALLOW.
  2. Ardından seccomp_rule_add(3), reddetmek istediğiniz her sistem çağrısı için bağlama bir kural ekleyin . Sen kullanabilirsiniz SCMP_ACT_KILLsyscall teşebbüs edilirse, süreci öldürmek için SCMP_ACT_ERRNO(val)belirtilen dönen başarısız syscall yapmak errnodeğeri, ya da başka actionkılavuz içinde tanımlanmış değeri.
  3. seccomp_load(3)Etkili hale getirmek için bağlamı kullanarak yükleyin .

Devam etmeden önce, bunun gibi bir kara liste yaklaşımının genel olarak beyaz liste yaklaşımından daha zayıf olduğunu unutmayın. Açıkça izin verilmeyen ve filtrenin atlanmasına neden olabilecek tüm sistem çağrılarına izin verir . Yürütmek istediğiniz alt işlemin filtreden kaçınmaya kötü niyetli olabileceğini düşünüyorsanız veya çocuklar tarafından hangi sistem çağrılarına ihtiyaç duyulacağını zaten biliyorsanız, beyaz liste yaklaşımı daha iyidir ve yukarıdakilerin tersini yapmanız gerekir: varsayılan eylemiyle filtre oluşturun SCMP_ACT_KILLve gerekli sistem çağrılarına izin verin SCMP_ACT_ALLOW. Kod açısından fark minimumdur (beyaz liste muhtemelen daha uzundur, ancak adımlar aynıdır).

Yukarıda bir örnek ( exit(-1)sadece basitlik uğruna hata durumunda yapıyorum ):

#include <stdlib.h>
#include <seccomp.h>

static void secure(void) {
    int err;
    scmp_filter_ctx ctx;

    int blacklist[] = {
        SCMP_SYS(open),
        SCMP_SYS(openat),
        SCMP_SYS(creat),
        SCMP_SYS(socket),
        SCMP_SYS(open_by_handle_at),
        // ... possibly more ...
    };

    // Create a new seccomp context, allowing every syscall by default.
    ctx = seccomp_init(SCMP_ACT_ALLOW);
    if (ctx == NULL)
        exit(-1);

    /* Now add a filter for each syscall that you want to disallow.
       In this case, we'll use SCMP_ACT_KILL to kill the process if it
       attempts to execute the specified syscall. */

    for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
        err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
        if (err)
            exit(-1);
    }

    // Load the context making it effective.
    err = seccomp_load(ctx);
    if (err)
        exit(-1);
}

Şimdi, programınızda, aşağıdaki gibi seccomp filtresini uygulamak için yukarıdaki işlevi çağırabilirsiniz fork():

child_pid = fork();
if (child_pid == -1)
    exit(-1);

if (child_pid == 0) {
    secure();

    // Child code here...

    exit(0);
} else {
    // Parent code here...
}

Seccomp ile ilgili birkaç önemli not:

  • Bir seccomp filtresi uygulandıktan sonra işlem tarafından kaldırılamaz veya değiştirilemez.
  • Filtre tarafından izin verilirse fork(2)veya clone(2)izin verilirse, alt süreçler aynı filtre tarafından kısıtlanır.
  • Eğer execve(2)izin verilir, mevcut filtre bir çağrı karşısında korunacaktır execve(2).
  • Eğer prctl(2)syscall izin verilir, süreç daha da filtreler uygulamak yapabiliyor.

2
Kum havuzu için kara liste mi? Genellikle kötü bir fikir, bunun yerine beyaz listeye eklemek istiyorsunuz.
Deduplicator

@Deduplicator Biliyorum, ancak beyaz liste yaklaşımı OP'nin durumu için çok iyi değil çünkü yeni dosya tanımlayıcıları açmaya izin vermemek istiyorlar. Sonunda bir not ekleyeceğim.
Marco Bonelli

Cevabınız için teşekkürler, buna ihtiyacım var. Bir beyaz liste, aslında istediğim uygulama için daha iyi. Sadece dosya tanımlayıcıları açmaktan daha fazla şey kısıtlaması gerektiğini aklımdan çıkarmadım.
jklmnn

@jklmnn evet, kesinlikle. Gerçekten socket(2)de bir de yaratabileceğini unuttum fd, bu yüzden de engellenmeli. Çocuk sürecini biliyorsanız, beyaz liste yaklaşımı daha iyidir.
Marco Bonelli

@MarcoBonelli Bir beyaz liste kesinlikle daha iyidir. Düşüncesizce, creat(), dup()ve dup2()tüm Linux sistem çağrıları bu dönüş dosya tanımlayıcılarıdır. Bir kara liste etrafında bir çok yol var ...
Andrew Henle
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.