5 Eylül 2017 Salı

Kernel ve Stack

Not : Bu yazı ile ilgili olarak Segmentation Fault başlıklı yazıya göz atabilirsiniz.


Stack Boyutu
Linux üzerinde stack boyutunu ayarlamak mümkün. Buradaki şekilde durum görülebilmektedir.

Address space layout randomization
Bu yöntemde stack'in başlangıç adresi, kullandığı guard page sayısı rastgele seçilerek, buffer overflow saldırılarına karşı tedbir alınıyor.

Stack'in Yönü
Çoğu mimaride stack aşağıya doğru büyür. Bunu görmek için şöyle yaparız.
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

static ptrdiff_t
stack_probe(uintptr_t stack_addr_from_main)
{
  int var;
  uintptr_t stack_addr_from_me = (uintptr_t)&var;

  return ((intptr_t) stack_addr_from_me) - 
         ((intptr_t) stack_addr_from_main);
}

int main(void)
{
  int var;
  uintptr_t stack_addr_from_main = (uintptr_t)&var;
  ptrdiff_t stack_delta = stack_probe(stack_addr_from_main);
  printf("Stack offset from one function call = %td\n", stack_delta);
  return 0;
}

Linux ve ulimit komutu
Linux üzerinde stack boyutunu ayarlamak için ulimit komutu kullanılabilir.
Windows ve Enhanced Mitigation Experience Toolkit
Buradaki soruda, EMET aracı kullanılarak, kaç tane stack guard sayfasının konulabileceği ayarlanmış.

Stack Clash
Açıklaması şöyle
Stack Clash is an exploit based on a fairly old technique. The memory used by a process is divided into two regions - the stack and the heap. One generally imagines the stack as growing downwards and the heap as growing upwards. What happens when the either grows enough to clash with the other? More generally, what happens when the stack grows enough to encroach into unrelated memory spaces? The original vulnerability is 12 years old, and the Linux kernel developers fixed it temporarily by using a guard page. However, researchers at Qualys have managed to exploit this despite the guard page.
Stackoverflow Olursa - C#
C#'ta stackoverflow olursa, JIT için kod derleyecek yeterli yer kalmadığı için kurtulmak mümkün değil.

Stackoverflow Olursa -Java
Java JIT kullanmak zorunda olmadığı için stackoverflow'dan kurtulabilir. Örnek:
public class Test
{
    public static void main(String[] args)
    {
        try {
            foo();
        } catch (StackOverflowError e) {
            bar();
        }
        System.out.println("normal termination");
    }

    private static void foo() {
        System.out.println("foo");
        foo();
    }

    private static void bar() {
        System.out.println("bar");
    }
}
C++ Windows
Stack'te yaratılan değişkenlerde buffer overflow olursa yakalanabilir.
Proje / C7C++ / Code Generation / Basic Runtime Cheks = Both yapılır.  Aşağıdaki örnek çalıştırılırsa stack hatası yakalanır.
int main (int argc, char* argv[]){
 char buf [1];
 buf [1] = 'A';
 return 1;
}
Programdan çıkarken Run-Time Check Failure #2 - Stack around the variable 'buf' was corrupted pop-up mesajı gelir.

Stack ve API
Aşağıda stack bilgisini alma ve atamayla ilgili bazı API açıklamaları var.

Windows 8
Stack boyutunu öğrenmek mümkün.
ULONG_PTR lowLimit;
ULONG_PTR highLimit;
GetCurrentThreadStackLimits(&lowLimit, &highLimit);

Posix pthread_getattr_np metodu
pthread_getattr_np ve pthread_attr_getstack metodlarını kullanarak bir threadin kullandığı stack boyunu öğrenmek mümkün.

Posix pthread_attr_setstack metodu
pthread_attr_setstack metodu ile bir threadin kullandığı stack boyutunu atamak mümkün.
pthread_attr_getstack metodu ile bir threadin kullandığı stack boyutunu öğrenmek mümkün.

Stack boyutunu atamak için kullanılacak stack'i kullanıcının yaratması gerekiyor.

Posix pthread_attr_setguardsize metodu
Bazı derleyiciler Buffer Overflow hatalarını yakalamak için Heap ve Stack segmentleri arasına "Guard Page" denilen veri yapıları yerleştirirler. Böylece stack bölümündeki bir taşmayı yakalamak mümkün olur.

pthread_attr_setguardsize metodu ile stack için guard alanı yaratmak mümkün.
How to set stack_size, stack_addr and guardsize when creating a thread başlıklı soruda bu konu daha iyi açıklanmış. Bu konu ile ilgili olarak Segmentation Fault başlıklı yazıya göz atabilirsiniz.

Compiler her zaman Stack Kullanmak Zorunda Değildir
Bir metod çağırıldığı zaman eski metod içindeki her şey stack'e atılır ve yeni metod'a geçilen parametreler de dahil olmak üzere yeni bir stack yaratılır diye biliyordum ancak c & gcc : Stack growth and alignment - for a 64 bit machine sorunda da görülebildiği gibi compiler yeni çağırılan metoda geçilen parametreleri ESI ve EDI register'larına yazarak stack kullanmadan bir metod da çağırabiliyormuş.What is exactly the base pointer and stack pointer? To what do they point? sorusuna verilen cevaplardan birisi olan şu cümle ile ne kast ettiğim daha iyi anlaşılabilir.
Generally (and this may vary from compiler to compiler), all of the arguments to a function being called are pushed onto the stack (usually in the reverse order that they're declared in the function prototype, but this varies).

Hiç yorum yok:

Yorum Gönder