Signal Handler'larda Yapılan 5 Kritik Güvenlik Hatası
Signal handler'lar işletim sistemi sinyallerine tepki veren, programın ana akışını kesip araya giren kod parçalarıdır. Basit görünseler de, burada yapılan hatalar buffer overflow'dan privilege escalation'a kadar ciddi açıklar yaratır. Sorunu şu: handler'lar senkron değildir, çoğu kütüphane fonksiyonu içlerinde güvenli değildir ve test etmesi zordur.
Async-Signal-Safe Kuralını Görmezden Gelmek
Signal handler'ın içinde `malloc()`, `printf()`, `pthread_mutex_lock()` gibi fonksiyonlar kullanmak tehlikeli. Bu fonksiyonlar thread-safe olabilir ama signal-safe değildir, yani sinyalin alındığı anda bir kütüphane fonksiyonunun ortasında bulunabilir, deadlock veya veri bozulması oluşur. POSIX sadece `write()`, `signal()`, `_exit()` gibi basit sistem çağrılarını güvenli kabul eder. Gerçek dünyada handler'ın içine sadece global bir `volatile sig_atomic_t` flag set etmelisin, asıl işlemi main loop'ta yap.
Race Condition ve Paylaşılan Veri
Main kod ve handler aynı global değişkeni değiştirebilir. Handler sırasında main thread'in değişkeni okuması veya yazması tutarsız durum yaratır. Çözüm: handler'da sadece `volatile sig_atomic_t` türünde değişkenler kullan. Bu tip, atomik okuma-yazma garantisi verir ve compiler optimizasyonlarını engeller.
Sinyal Maskeleme Unutmak
Handler içinde aynı sinyal tekrar gelirse? Veya başka bir sinyale yanıt verirken ilki kaçırılır mı? Sinyal maskeleme (`sigprocmask()` veya `sigaction()` ile `sa_mask`) handler çalışırken hangi sinyallerin engelleneceğini tanımlar. Bunu ayarlamayan kod, nested handler'lar ve beklenmeyen sıralama riskine girer.
Çıkış Durumunu Bozma
Handler'da `errno` değiştirilirse, main kod hatalı bir hata kodu okur. Ya da handler `exit()` çağırırsa, cleanup kod çalışmaz. Güvenli handler'lar `errno` değerini kaydeder, işi bitirince geri yükler. Acil durumlar için `_exit()` kullan, bu `atexit()` handler'larını çalıştırmaz ama en azından veri bozulmasını engeller.
Sinyal Delivery Zamanlamasını Kontrol Etmemek
Sinyal ne zaman gelir? Hiç gelmezse? Veya çok hızlı art arda gelirse? Standart sinyaller birleştirilir, aynı sinyalin birden fazla gelişi tek bir handler çağrısına dönüşür. Real-time sinyalleri (`SIGRTMIN` ile `SIGRTMAX`) arasında) bir kuyruk tutulur ama yine de sınırı vardır. Handler'ı tasarlarken "bu 100 kez çağrılabilir" diye düşün, değişken durumunu buna göre yönet.
Sonuç
Signal handler'lar sistem programcılarının en sık hata yaptığı yer. Basit kural: handler'ı mümkün olduğunca kısa tut, sadece flag set et, asıl işi main loop'ta yap. Test ederken `kill -SIGUSR1` ile elle gönder, race detector kullan, `valgrind` ile bellek kontrol et. Çoğu modern kod signal'ı event loop veya `signalfd()` ile ele almayı tercih ediyor, bu daha güvenli ve tahmin edilebilir.
0 yorum