¿Las condiciones de carrera basadas en memcpy () son explotables para causar la ejecución remota de código?

10

Supongamos que tengo el siguiente pseudocódigo en la parte de confianza de un recinto de seguridad que evita que los códigos no confiables llamen a mprotect() y mmap() y ptrace() directamente (no se puede acceder al mutext desde la memoria del espacio aislado)

//src and dest are user controlled but must be valid.
TrustedPart_for_safe_jit(void * mutext, uint8_t *src,uint8_t *dest, uint32_t size) // in the current case, *dest targets a PROT_NONE memory region
{
    MutexLock(mutext);
    ValidateOpcodesOrCrash(src,size); // uses calls to mmap on size internally. Contains many different loops and use several 10k thousands lines of codes in the trusted part of the sandbox : this is the longest part. Please also note that src is write protected while being in this function.
    unwriteprotect(dest,size); // calls many sandbox’s internal functions

    SafeMemcpy(src,dest,size); // THIS IS the function which contains the race condition

    asm("mfence");
    unEXECprotect(dest,size); // involve write protecting as well as allowing reading
    MutexUnlock(mutext);
}

SafeMemcpy(uint8_t *src,uint8_t *dest, uint32_t size) // the data to be copied cannot exceed 128Mb
{
    if(!CheckUserTargetPointToValidMemroyRange(dest,size) {
        uint8_t *src_ptr=src;
        uint8_t *dest_ptr=dest;
        uint8_t *end_ptr=des+size;
        while (dest_ptr < end_ptr) { // that loop should execute very fast
            *(uint32_t *) dest_ptr = *(uint32_t *) src_ptr;
            dest_ptr += 4;
            src_ptr += 4;
        }
    }
}

Esa parte es responsable de permitir que código no confiable use ᴊɪᴛ compilación.
El punto en el que no se confía no está suspendido.

Como saben, cuando 2 subprocesos utilizan memcpy() con el mismo destino, generan datos aleatorios. En ese caso, dichos datos podrían contener instrucciones como int 0x80 , lo que permitiría escapar de la zona de pruebas.

Cosas que pensé hasta ahora:

  • Escriba datos en un archivo y léalos con la llamada del sistema de lectura a través de la zona de pruebas. Si la memoria aún está protegida contra escritura, el programa no falla. Esto implicaría realizar un bucle e incluso si los datos que se van a copiar pueden tener un tamaño de 128 MB, no estoy seguro de que funcionen debido a la sobrecarga de la llamada. Una alternativa sería crear el código varias veces e intentar leer. con varios tiempos , pero no tengo idea de cómo seleccionar la ventana de tiempo inicial.
  • Use futex ... Pero no se pudo encontrar si futex se puede usar para verificar el valor de la memoria no asignada. Tampoco estoy seguro de que el hilo pueda despertarse antes de que la memoria quede protegida contra escritura.

Entonces, ¿es posible planificar la ventana de tiempo para las condiciones de carrera memcpy?

    
pregunta user2284570 20.02.2017 - 02:44
fuente

2 respuestas

2

Según lo que veo aquí, puede modificar * src después de que ValidateOpcodesOrCrash terminó de verificar esa parte de la memoria pero antes de que se inicie SafeMemcpy.

No sé cómo se implementa ValidateOpcodesOrCrash, pero presumiendo que simplemente recorre [src,src+size] y busca instrucciones ilegales, entonces puede llamar con un TrustedPart_for_safe_jit large size , ocupado esperar unos pocos cientos de CPU ciclos, y luego comience a sobrescribir *src que ValidateOpcodesOrCrash probablemente haya terminado de verificar. Si ValidateOpcodesOrCrash hace algo más complicado, puede averiguar qué secuencia de instrucciones será la más rápida y lenta para que ValidateOpcodesOrCrash pueda verificar, colocar la más rápida al frente y muchas de las instrucciones más lentas hasta el final. Es probable que no tenga que esperar a que se complete ValidateOpcodesOrCrash antes de comenzar a sobrescribir src.

    
respondido por el Lie Ryan 21.03.2017 - 03:56
fuente
0

(Descargo de responsabilidad: no soy un profesional de seguridad, solo soy un estudiante con algunos conocimientos de C)

Creo que esto es probablemente explotable, al menos para causar un bloqueo. Para corregir el error, necesita:

  • suspende todos los subprocesos que no son de confianza, mientras que dest se puede escribir.
  • o haga que TrustedPart_for_safe_jit devuelva la memoria ejecutable recién asignada (asumo que el código que no es de confianza no está permitido a toser direcciones de máquinas arbitrarias como punteros).

Eso significa que, en lugar de usar un mutex, debes detener el mundo.

    
respondido por el Demi 19.03.2017 - 20:13
fuente

Lea otras preguntas en las etiquetas