stackoverflow - stack overflow wikipedia
Establezca el tamaƱo de pila con setrlimit() y provoque un desbordamiento de pila/segfault (2)
Creo que setrlimit
mueve los "punteros de recursos" pero no aplica los nuevos límites hasta que exec
una nueva copia del programa.
#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;
}
Y una prueba de ejecución:
$ ./a.out lim: 8388608 / -1 foo 1: 42 lim: 65536 / 65536 foo 2: 42 Killed
Por qué el proceso se mata antes de imprimir los límites (y antes de llamar a foo), no lo sé.
En el siguiente ejemplo, intento establecer el tamaño de pila en 1kb.
¿Por qué ahora es posible asignar una matriz de entradas en la pila con tamaño 8kb
en foo()
?
#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);
}
El límite se establece de inmediato, pero solo se verifica cuando se intenta asignar una nueva pila o tratar de hacer crecer la pila existente. Un grep para RLIMIT_STACK ( o una búsqueda de identificador LXR ) en las fuentes del kernel debería indicarlo.
Aparentemente, el tamaño inicial de la pila es el que se necesita para el nombre de archivo + env strings + arg strings más algunas páginas adicionales asignadas en setup_arg_pages
(20 páginas en 2.6.33 1 , 2 , 128 Kb en 2.6.34 3 ).
En resumen:
initial stack size = MIN(size for filename + arg strings + env strings + extra pages, MAX(size for filename + arg strings + env strings, RLIMIT_STACK))
dónde
size for filename + arg strings + env strings <= MAX(ARG_MAX(32 pages), RLIMIT_STACK/4)
Además, los núcleos con el parche de exec-shield
Ingo Molnar (Fedora, Ubuntu, ...) tienen un EXEC_STACK_BIAS " adicional (2 MB más para cubrir los efectos de aleatorización)" , consulte la llamada a la nueva función over_stack_limit()
de acct_stack_growth()
( [Ubuntu1] , [Ubuntu2] , [Ubuntu3] ).
He editado el programa original para mostrar esto:
#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);
}
Lo que resulta en:
$./rl
foo: 42
$./rl -l
limiting stack size
Segmentation fault
$