2010-11-07 13 views
11

Aşağıdaki örnekte stacksize'yi 1kb olarak ayarlamaya çalışıyorum.Yığın boyutunu setrlimit() ile ayarlayın ve yığın taşması/segfault'unu provoke edin

Neden 8kb boyutunda foo() numaralı yığında bir dizi intr'leri ayırmak mümkün?

#include <stdio.h> 
#include <sys/resource.h> 

void foo(void); 

int main() { 
struct rlimit lim = {1024, 1024}; 

if (setrlimit(RLIMIT_STACK, &lim) == -1) 
    return 1; 

foo(); 

return 0; 
} 

void foo() { 
unsigned ints[2048]; 

printf("foo: %u\n", ints[2047]=42); 
} 
+0

şimdi reklamı olarak bu işe yaramazsa neden bulmaya bağımlıyım, teşekkür ederiz

Bunu göstermek için orijinal programı kaydetmiştiniz adam (2) setrlimit. Neyse ki, gcc yığın boyutunu belirtebilmenizi sağlar :) –

+0

Bu kez daha fazla desteklendiğinden daha sık bir soru. İlginç. –

cevap

4

Sınır hemen belirlenir, ancak yalnızca yeni bir yığın ayırmaya veya varolan yığını büyütmeye çalışırken denetlenir. Çekirdek kaynakları üzerinde RLIMIT_STACK (or a LXR identifier search) için bir grep söylemelidir.

Görünüşe göre, yığının başlangıç ​​boyutu 2.6.34 3 üzerinde 2.6.33 1, 2, 128 Kb olarak dosya adı + env dizeleri + arg dizeleri artı setup_arg_pages (20 sayfalarında tahsis bazı ekstra sayfalar için gereken her türlü olduğu).

size for filename + arg strings + env strings <= MAX(ARG_MAX(32 pages), RLIMIT_STACK/4) 

Ayrıca, Ingo Molnar en exec-shield yama (Fedora, Ubuntu, ...) ile çekirdekleri ilave EXEC_STACK_BIAS sahip

initial stack size = MIN(size for filename + arg strings + env strings + extra pages, MAX(size for filename + arg strings + env strings, RLIMIT_STACK)) 

"(2MB daha kapsayacak şekilde: Özetle

rasgele efektler.) ", ([Ubuntu1], [Ubuntu2], [Ubuntu3]) over_stack_limit() işlevine yapılan çağrıya bakın. sonuçlanan

#include <stdio.h> 
#include <sys/resource.h> 

void foo(void); 

int main(int argc, char *argv[]) { 
     struct rlimit lim = {1, 1}; 


     if (argc > 1 && argv[1][0] == '-' && argv[1][8]=='l') { 
       printf("limiting stack size\n"); 
       if (setrlimit(RLIMIT_STACK, &lim) == -1) { 
         printf("rlimit failed\n"); 
         return 1; 
       } 
     } 

     foo(); 

     return 0; 
} 

void foo() { 
     unsigned ints[32768]; 

     printf("foo: %u\n", ints[2047]=42); 
} 

:

$./rl 
foo: 42 
$./rl -l 
limiting stack size 
Segmentation fault 
$ 
+1

Hayır, aslında, varolan bir yığını büyütmeyi başardım. Şimdi bu problemle kemikten çıkmayacak bir köpek gibiyim. –

+0

@Tim Post: yığının büyüdüğünden emin misin? Düzenlenmiş cevabımı görün, ilk yığında fazladan boşluk var. – ninjalj

+0

Evet, her iki durumda da 16k, aynı sonucu genişlettim. –

4

Ben setrlimit "kaynak işaretçileri" hamle ancak exec programın yeni bir kopyasını kadar yeni sınırları geçerli değildir düşünüyorum.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/resource.h> 

void foo(int chk) { 
    unsigned ints[2048]; 
    ints[2047] = 42; 
    printf("foo %d: %u\n", chk, ints[2047]); 
} 

int main(int argc, char **argv) { 
    char *newarg[] = { "argv[0]", "one", "two" }; 
    char *newenv[] = { NULL }; 
    struct rlimit lim; 

    newarg[0] = argv[0]; 
    getrlimit(RLIMIT_STACK, &lim); 
    printf("lim: %d/%d\n", (int)lim.rlim_cur, (int)lim.rlim_max); 
    switch (argc) { 
    case 1: /* first call from command line */ 
     lim.rlim_cur = 65536; 
     lim.rlim_max = 65536; 
     if (setrlimit(RLIMIT_STACK, &lim) == -1) return EXIT_FAILURE; 
     newarg[2] = NULL; 
     foo(1); 
     execve(argv[0], newarg, newenv); 
     break; 
    case 2: /* second call */ 
     lim.rlim_cur = 1024; 
     lim.rlim_max = 1024; 
     if (setrlimit(RLIMIT_STACK, &lim) == -1) return EXIT_FAILURE; 
     foo(2); 
     execve(argv[0], newarg, newenv); 
     break; 
    default: /* third call */ 
     foo(3); 
     break; 
    } 
    return 0; 
} 

Ve bir prova: süreç limitlerini (ve foo çağırmadan önce) yazdırmadan önce öldürülmeden Neden

 
$ ./a.out 
lim: 8388608/-1 
foo 1: 42 
lim: 65536/65536 
foo 2: 42 
Killed 

, bilmiyorum.

+0

Benzer olduğundan şüphe duydum ve sadece hiç fark etmeyen fork() ile denedim. Setrlimit() 'in neden sadece "exec" ile değil, parent tarafından oluşturulan süreçleri etkilediğini anlayamıyorum, ama durum böyle görünüyor. –

+0

GDB ile "Foo 2: 42" satırından sonra "Program normal olarak çıkarıyorum" - yok, hiçbir segfault yok – tur1ng

+0

@ tur1ng: "newarg [0] = argv [0];" ifadesini ana başlığın başında eklemeyi deneyin. İkilinize "a.out" denilmediğinden şüpheleniyorum – pmg