2010-10-06 17 views
12

Estoy tratando de evitar que el código del estudiante se ejecute de forma alocada con las asignaciones y que detenga mi máquina de prueba. He intentado¿Cómo puedo limitar la memoria adquirida con `malloc()` sin limitar también la pila?

setrlimit(RLIMIT_DATA, r); 

donde r es una estructura que sostiene los límites. Pero, lamentablemente, aunque este límite impide que se asignen brk y sbrk, la biblioteca C solo pasa a mmap y se mantiene al asignar.

También he intentado

setrlimit(RLIMIT_AS, r) 

y esto detiene el proceso en sus pistas, pero este remedio es demasiado severa — es imposible que el proceso para recuperarse del error ENOMEM porque no hay espacio en la pila de las llamadas que hace el código al encontrar un valor NULL devuelto desde malloc().

Tengo controles limitados sobre los binarios, por lo que si es posible hacerlo con una llamada al sistema, lo preferiría. Pero necesito algunos medios para limitar la asignación sin destruir la capacidad de recuperación del proceso. ¿Alguien tiene sugerencias?

ACTUALIZACIÓN: me encontré con algo que se llama failmalloc, pero no es muy sofisticado, y aunque puedo provocar un fallo con él, siempre me sale un error de segmentación que GDB no puede diagnosticar.

nueva actualización: me encontré con que setrlimit(RLIMIT_AS, r)hace parecen hacer el trabajo que quiero, al menos en algunos casos — las violaciones de segmento que estaban ocurriendo después fueron causadas por un fallo en un módulo sin relación. A menos que alguien encuentre algo interesante (o una razón para mantener la pregunta), probablemente borre la pregunta.

+0

Si solo está tratando de evitar que los programas abusivos/defectuosos anulen el sistema, no se moleste en dejar que se recuperen del 'malloc' fallido. Solo deja que el SO los mate y termine con eso. Un programa correcto, presumiblemente, nunca debería llegar al límite de todos modos. –

+0

Muchos estudiantes envían programas incorrectos. Si descargan núcleo, obtienen ceros. Si se recuperan y abortan, obtienen crédito parcial. –

Respuesta

3

¿Se puede forzar una macro en los estudiantes desprevenidos? :-)

#define malloc(bytes) limited_malloc(bytes) 

y también una definición para limited_malloc que limita lo que puede hacerse.

4

Basándose en la idea utilizada por failmalloc, se podría utilizar la variable y función LD_PRELOAD* entorno de interposición para construir una envoltura alrededor de malloc() e imponer ninguna limitación allí.

Debería cargar dinámicamente un puntero al malloc() original utilizando dlsym(). No se puede llamar directamente al malloc() original del contenedor porque se interpretará como una llamada recursiva al propio contenedor.

#define _GNU_SOURCE 
#include <stdio.h> 
#include <stdint.h> 
#include <dlfcn.h> 

void * malloc(size_t size) 
{ 
    static void * (*func)(size_t) = NULL; 
    void * ret; 

    if (!func) 
    { 
     /* get reference to original (libc provided) malloc */ 
     func = (void *(*)(size_t)) dlsym(RTLD_NEXT, "malloc"); 
    } 

    /* impose any necessary restrictions before calling malloc */ 
    ... 

    /* call original malloc */ 
    ret = func(size); 

    /* impose any necessary restrictions after calling malloc */ 
    ... 

    return ret; 
}

* Tenga en cuenta que LD_PRELOAD debe especificar la ruta completa a la biblioteca de interposición, y que la interposición biblioteca está deshabilitada para los programas setuid con el fin de evitar problemas de seguridad.


Un alternative a la utilización de dlsym() sería utilizar la opción GNU enlazador --wrap symbol.

+1

Las fuentes de valgrind deberían contener algo similar a ese enfoque, supongo. –

Cuestiones relacionadas