Bu sitede bulunan bütün bilgi ve araçlar SADECE eğitim amaçlıdır, ne niyetle kullandığınız sizi bağlar ve sizin sorumluluğunuzdadır! [Demedi deme]

Hacker'ın Olmazsa Olmazı - Kernel #2 Ol Demek Yetmiyor

Tarih 14 Mart 2014. KATEGORI Bilisim

Isındırma turlarının ardından process management yani işlem yönetimi ile alakalı olan bu yazımızla kerneli incelemeye başlıyoruz.Müşterinin bol olduğu yerde nasıl ki dükkan sahibi insanları sopayla sıraya sokar geyiği yapılıyorsa bizim kernelin de müşterisi her zaman bol olduğuna göre bakalım o bu işi nasıl yapıyor, bu yazımızda irdeleyelim deyu deyu başlıklarımıza geçelim.

Ol

Her ne kadar Yaratıcının birşeyi istemesi durumda ol demesi yeterliyse de biz insanların bazı sebeplere başvurma ihtiyacı kaçınılmaz bir gerçektir.Biz yani kullanıcılar [ya da kernel] birşeyi oldurmak istediğinde bir sırayı, bir düzeni takip etmek zorundayız.

Bir işlem yapacağımız zaman, en basitinden ls komutunu çalıştırdığımızda, takip ettiği sırayı kontrol ederseniz [strace komutu ile] daha ilk satırda execve komutunu görürsünüz.Bu başlığımızda işlem başlatma için kullanılabilecek seçenekleri sıralayıp az da olsa detaylarına girelim.

İlk seçeneğimiz execve'nin de içinde bulunduğu exec serisi oluyor.Kendi içerisinde de birçok alternatif barındıran bu seri hakkında bilgi almak için herhangi bir seçeneği [man execlp gibi] sorguladığınızda hepsiyle alakalı kısa bilgileri görebilirsiniz.

İkinci seçeneğimiz fork yani çatal fonksiyonunu kullanmak.Bir çatalı düşündüğünüzde nasıl ki sapı tek parça halinde gelirken uçlarda birbirine benzer parçalardan oluşuyorsa, forkta da mevcut işlemin kendisine benzer bir çocuk sahibi oluyor diyebiliriz.Çocuk benzetmesini özellikle kullandım, çünkü mevcut işleme parent yani ebeveyn, yeni oluşturulan işleme ise child yani çocuk deniliyor.

Hepimiz ebeveynlerimize benzesek de bazı farklılıklarımız mevcuttur.Aynı durum burada da karşımıza çıkıyor.Mesela babanın PID numarası yani Process Identifier yaniyani İşlem Kimliği [bu tercümeler öldürecek beni] çocuğunkinden farklıdır.Bunun haricindeki farklılıkları öğrenmek ve detay isteyenler man fork komutuna başvurabilir.

Üçüncü seçeneğimiz olan vfork ise kernel 2.3 sürümünden evvel sıkça kullanılan, fork fonksiyonunun yaptığı bazı işlemleri yapmayarak hız elde etmek için kullanılan, fakat COW yani Copy-On-Write tekniği kullanılmaya başlandıktan sonra eski ününü kaybeden bir fonksiyondur.

Dördüncü seçeneğimiz ise clone isminde, adından da anlaşılacağı üzere klonlama yapan, asıl hedefi thread oluşturmak olan bu fonksiyonu anlamak için bir örnek verelim.Tarayıcıyı açtınız, önce feysbuka girdiniz, onu kapatmadan tivıtıra da bakayım dediğinizde yeni bir tarayıcı açmak yerine yeni bir tab açıyorsanız, işte orada clone fonksiyonu kullanılmaktadır.

Fork fonksiyonu kullandığınız zaman yine clone çağrılmakta fakat ilave olarak SIGCHILD [evlat muhabbeti] seçeneği eklenmektedir.Bu seçeneklerin hepsinin amacı işlem başlatmaktır, doğal olarak aralarında ufak tefek farklar bulunsa da hedef aynıdır.Basitten iki örnek yapalım:

[Execve için kaynak kodumuz]
#include <stdio.h>

int main(void)
{
   printf("Benim PID : %d\n", getpid());
   printf("Baba  PID : %d\n", getppid());
   execve("./xve",NULL,NULL);
   return 0;
}
root@kali:~# gcc xve.c -o xve && ./xve
Benim PID : 7342
Baba  PID : 7064
Benim PID : 7342
Baba  PID : 7064
Benim PID : 7342
Baba  PID : 7064
Benim PID : 7342
[Ctrl + C ile looptan kurtuluyoruz]

[Fork için kaynak kodumuz]
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void)
{
	pid_t pido;
	int status;
	printf("Islem basladi, mevcut bilgiler\n");
	printf("Mevcut PID : %d\n", getpid());
        printf("Baba   PID : %d\n", getppid());

	pido = fork();
	if (!pido)	{
		printf("Evlat basladi, (fork)\n");
		printf("Mevcut PID : %d\n", getpid());
   		printf("Baba   PID : %d\n", getppid());
			}
	else 	{
		wait(&status);
		}
	return 0;
}
root@kali:~# gcc fork.c -o fork && ./fork
Islem basladi, mevcut bilgiler
Mevcut PID : 7352
Baba   PID : 7064
Evlat basladi, (fork)
Mevcut PID : 7353
Baba   PID : 7352

root@kali:~/proses# strace ./fork
...
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb75ad938) = 3569

Basit iki örneğimizde görüldüğü üzere execve'de baba yerini oğluna bırakırken, fork kullandığımızda baba-oğul ilişkisi devam etmektedir.Fork kullandığımız yerde de clone fonksiyonunun kullanıma dikkat lütfen diyerek bir sonraki başlığımızda kernelde bu işler nasıl oluyor, buyrun hep beraber inceleyelim.

Bu seçeneklerin haricinde bir de pthread_create fonksiyonuna bir göz atmanızı tavsiye etmek durumundayım.Teklif var ısrar yok durumu..

Eşit mi Adil mi

İşlem başlatmayla ilgili verdiğimiz kısa bilgilerden sonra kernel işlemleri neye göre değerlendiriyor onu bir öğrenelim, sonra da sıraya sokmaya nasıl yapıyor ona bakalım, binaenaleyh bu başlığın da hakkını vermiş olalım.

Hepimizin kabul ettiği üzere [darvinciler hariç] ilk insan, dedemiz Hz. Adem (a.s.)'dir.Baba-oğul ilişkilerinden bahsettik ya, kernelin de bütün işlemlerin atası olarak başlattığı ilk işlem PID numarası 1 olan init işlemidir.Arkadan ne gelecekse ya oğul ya torun nispetinde init işlemine bağlanmak zorundadır.

Kernel işlemleri öncelikle real-time ve non real-time olarak ikiye ayırmaktadır.Örnek verelim, bir yazılım hazırladınız, Airbus A-380 gibi dev bir uçağın piste iniş sırasında dengesiyle ilgili pilota yardımcı olduğunu varsayalım.Tam inişe geçildiği sırada kernel sebebi ne olursa olsun bu yazılımı beklemeye almamalı, bütün kaynaklarını emrine vermeli.İşte bu tür yazılımlara hard real-time process denilmekte FAKAT linux kernel [vanilla kernel] bu tür bir destek VERMEMEKTEDİR!

Bir örnek daha verelim; mesela CD yazdırmak istediniz ve yazım sırasında diğer programlar sistem yükünü arttırıp kerneli meşgul ederse, belli bir rate hızının altına inerseniz, CDnin elinizde patlama ihtimali çok yüksektir.Bu tür işlemlere soft real-time process denilmektedir.Bu tür işlemlere öncelik vermek için kernel 2 kriter kullanmaktadır.Bunlardan birisi priorities diğeri ise nice değerleridir.Assembly serinin son yazısı olan Reys Reis'te nice mevzusunu örneklendirmiştik, isteyen inceleyebilir.

Önceliğin önem taşıdığı bu tarz uygulamaların haricinde kalan diğer işlemlere, mesela uzun ve karmaşık hesaplamalar yapan bir uygulama farzedelim, non real-time process denmekte, bu arkadaşlar kernelin eşitlik ilkesine göre değil adil oluşuna göre sıralarını beklemek zorundadır.Biraz detaya girersek, kernel 2.6.23 itibariyle işlemleri sıraya sokma işini completely fair scheduler denilen yöntemle yapmaktadır.Burada hedef sistem kaynaklarını önce kullanıcı sayısına göre dağıtıp sonra da her kullanıcının işlem sayısına göre ayarlamaktadır.

Temel hedef interactive yani kullanıcının etkileşimde olduğu uygulamaları, mesela metin editörü gibi, uygulamaları mümkün olduğu kadar öne alarak sistemin gecikme olmaksızın çalıştığı izlenimi sağlamak, diğer bir taraftan bekleme sürelerine göre diğer işlemlere de cevap vererek adaleti sağlamak. Konuyla alakalı bu resim mutlak eşitliğin nasıl bir saçmalık, işin doğrusunun adil davranmak olduğunu göstermektedir.

Edebiyat karın doyurmuyor arkadaşlar, işin muhabbet kısmını bitirdiğimize göre gelelim kernel kaynak kodunda önemli noktalara değinmeye.Mevzu işlemler olunca spotları çevirmemiz gereken yer include/sched.h başlık dosyasında task_struct bölümüdür.Dibine kadar inmem lazım diyen cengaverler cross reference'dan incelemeyi bu adresten yapabilirler.Küçük bir kısmını buraya buyur edelim:

struct task_struct {
	volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
	void *stack;
	atomic_t usage;
	unsigned int flags;     /* per process flags, defined below */
	unsigned int ptrace;
	...

Malumunuz herşeyi burada anlatacağımıza göre ilk değişkenimiz olan state mevzusuna bir bakalım.Bir işlem kernel gözüyle ya runnable yani avını izleyen çita modunda, ya stopped yani kırmızı ışıkta durmuş modunda ya da unrunnable yani pert modunda olabilir.Stopped durumu ile unrunnable arasındaki farkı şöyle açıklayabiliriz; birisi dışarıdan bir müdaheleyi beklerken, mesela harddiskten bilgi gelmesini bekleme durumu gibi, diğerinde ise zombie dediğimiz hastayı kaybettik durumu mevcuttur.Peki neden ölü dememişler de zombie demişler diye bi sor hele, çünkü elinden bütün kaynakları kernel tarafından zorla alınmış olmasına rağmen varlığını sonlandırmamakta ısrar eden programcıklara başka denecek laf bulamamışlar.Umarım anladınız, yoksa google her zaman emrinizde..

Kaynak kod incelemesinde başka nerelere bakmamız lazım diyenlere doktorlar şu iki başlığı tavsiye ediyorlarmış; sys_fork ve sys_clone.İşinizi kolaylaştırmak adına söylüyorum [istesem söylemem] bu iki arkadaş da do_fork fonksiyonunu çağırır, gidin onu bırkalayın.Zahmet edip bunları da cross reference'dan kendiniz bulunuz diyelim devam edelim.

Bazı bilgileri kernel, userland yani kullanıcılar diyarına sunuyor.Mesela işlemlere ait limitleri öğrenebilmek için /proc/PID/limits dosyasını sorgulayabilirsiniz.O kadar çok detay var ki hangi birini yazsam modunda olduğumdan mütevellit meraklı arkadaşlara önce Allah sonra google yardımcınız olsun diyorum.Yazıyla alakalı hazırladığımız programımız için bir sonraki başlığa geçelim.

Yat Kalk

Kernel serisine başlarken önce hedefi tanımamız gerektiğini, bu yüzden saldırıdan ziyade incelemeler yapacağımızı fakat yeri geldiğinde çakallıklardan bahsedeceğimizi söylemiştim.Bir önceki seride çokça debugger kullandık, programı durdurduk, registerlara baktık, devam et dedik,kısaca yatırdık kaldırdık. Bunun haricinde işleyiş sırasını ve detayları görmemizi sağlayan strace programını artık bilmeyeniniz yoktur.Hem debuggerlarda hem de stracede baştacı edeceğimiz fonksiyon ptrace fonksiyonudur.

Process trace'in kısa hali olan ptrace, içinde eşşek yükü kadar detay barındıran, meraklısına man ptrace ile hepsini anlatan ama örneklendirmenin çok az olduğu şahane bir fonksiyon.Bu canavarla neyi nasıl yaptığımızı basitçe (!) gösteren programın kaynak kodunda paylaştım. Zahmet edip indireceksiniz, bırkalayacaksınız, kıpraştıkça ufkunuz genişleyecek, önünüz açılacak [seçimler öncesi biraz vaat modu takılalım].

Programın kaynak kodu, Full Nelson kernel exploitinin yazarı Nelson Elhage ağabeyimize ait.Zaten credit bölümünde de adresi paylaştım,isteyenler kaynağa da göz atabilir.<./p>

root@kali:~/proses# ./estreys ls
syscall(11) = -2
...
syscall(4) = estreys  estreys.c  fork  fork.c  xve  xve.c
45
syscall(6) = 0
syscall(91) = 0
syscall(6) = 0

Yol göstermesi babında hazırladığımız yazımızın sonuna gelmiş bulunuyoruz çoksaygıdeğer okuyucular, bir sonraki yazıda görüşmek dileğiyle sağlıcakla kalın.

Oynatalım Uğurcum

Yazı için hazırlanan videoyu YouTube'dan izleyebilirsiniz.

Yazı için hazırlanan estreys programının kaynak kodunu buradan indirebilirsiniz.

Thread konusunda eski de olsa güzel bir Türkçe kaynak, ilgilenen arkadaşlar buradan inceleyebilir.

Bir yorum yapın

Misafir olarak yorum yapıyorsunuz.