02 Mayıs 2007

process'ten process'e signal (sinyaller) öğrenmek

Merhaba, geçenlerde bilgisayarımda çalışıyordum ve aklıma sinyaller ile ilgili şeyler geldi. Mesela hangi process hangi process'e ne sinyali göndermiş, kim kime SIGKILL yapmış kim SIGHUP (ve bir sürü sinyal..) yapmış görmek istedim ve çekirdekte küçük bir değişiklikle bu özelliği elde ettim.
Sonuçta dmesg çıktısında hangi process hangi process'e ne göndermiş görebileceğiz.
Öncelikle sinyal nedir nasıl gönderilir bilmeyenler için onu belirteyim. kill sistem çağrısıyla gönderilir. Sinyali alan process handle ediyorsa eder (event-driven programlama gibi).
Not: Bazı sinyaller handle edilemez, SIGKILL (meşhur 9. sinyal) gibi.
Kısa bir sinyal anlatımından sonra konumuza dönelim. Şimdi bu kill fonksiyonunun çekirdekteki karşılığı olan sys_kill fonksiyonuna biraz ekleme yapalım ki her kill çağrılışında bizim eklediklerimiz de yapılsın.
Çekirdek kaynak kodumuzdaki kernel/signal.c dosyasını açıyoruz ve sys_kill fonksiyonunu buluyoruz.

struct task_struct *task;

task = find_task_by_pid(pid);
if (task)
printk(KERN_DEBUG "SIGNAL: %d from pid: %d (%s) to pid: %d (%s)\n", sig, current->pid, current->comm, pid, task->comm);
else
printk(KERN_DEBUG "SIGNAL: %d from pid: %d (%s) to pid: %d\n", sig, current->pid, current->comm, pid);

bu kodu ekliyoruz.
Bu kadar karışık olsun istemiyorsanız sadece else'ten sonra gelen tek satır da yeter. Üstte kalan kısım sadece sinyalin gittiği process'in adını alabilmek için.
Bunu yaptıktan sonra kernel outputu çok sık sinyallerle dolacaktır (rahatsız edici bir durum). Çünkü sinyaller çok fazla kullanılıyor.
Mesela en basitinden bir terminalde iken CTRL+C ye basın. Prompt bir satır aşağıya kayacaktır. dmesg yaptığımızda kabuğumuzun pid'inden kendine 2 nolu sinyal geldiğini göreceğiz.

SIGNAL: 2 from pid: 6029 (bash) to pid: 6029 (bash)

bendeki çıktı böyle oldu. Kendisine SIGINT (2 nolu sinyal) gelmiş bulunuyor. Hangi numaralı sinyalin hangi sinyal olduğuna signal.c dosyasının üstündeki tablodan bakabilirsiniz.

Bu arada bunun daha gelişmişi ya da daha düzenlisi diyeyim için şunlar yapılabilir:
printk ile değil de proc üzerinden ya da sysfs üzerinden haberleşen bir yapı çok güzel olurdu (kernel space'ten, user space'e proc ile haberleşmek). Bir de user space daemon yazmak lazım log tutan. Böylece kernel output'unu da kirletmemiş oluruz.

İyi çekirdek hacklemeler :)