[ zvrba @ 10.08.2004. 09:49 ] @
Na linuxu i FreeBSD-u (i ostalima koji podrzavaju modify_ldt syscall na x86 arhitekturi) je moguce ostvariti non-executable stack iskljucivo iz user-modea jednostavnim smanjivanjem velicine code segmenta. Treba samo staviti da code segment zavrsi tamo gdje pocinje stack (obicno na 3GB - 8MB). Ako se pokusa izvrsavati kod sa stacka, adresa izlazi izvan dozvoljene granice code segmenta i procesorov segmentacijski mehanizam dize general protection fault - program dobije SIGSEGV. Za dodatnu sigurnost treba postaviti "osiguranim" procesima stack limit na 8 MB (ili koliko vec treba - tada se treba prilagoditi i granica code segmenta). Jer inace program moze zauzeti dovoljno stacka i tako ga prosiriti u code segment. Evo primjer koda za linux: Code: #include <stdio.h> #include <string.h> #include <asm/ldt.h> #include <linux/unistd.h> void test() { int ret = 0xC3C3C3C3; /* C3 je kod za RET instrukciju */ void (*fn)(void) = &ret; printf("trying stack call..."); fflush(stdout); fn(); printf("done!!\n"); } int main() { struct modify_ldt_ldt_s ldt; printf("Before modify_ldt: "); test(); ldt.entry_number = 1; ldt.base_addr = 0; ldt.limit = 0xBF800; /* 3GB - 8MB */ ldt.seg_32bit = 1; ldt.contents = 2; /* execute/read */ ldt.read_exec_only = 0; /* allow read in exec segments */ ldt.limit_in_pages = 1; ldt.seg_not_present = 0; ldt.useable = 0; if(modify_ldt(1, &ldt, sizeof(ldt)) < 0) { perror("modify_ldt"); exit(1); } /* Nema instrukcija tipa movw %ax,%cs. Mora se izvesti FAR JUMP. */ printf("After modify_ldt: "); asm("ljmp $0x0F, $0f; 0: nop"); test(); return 0; } |