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?