RAP es muy similar a un canario de pila, excepto que está diseñado para prevenir contra ROP.
EDIT : después de hablar con spender desde grsecurity, resulta que lo que estoy describiendo aquí es un subconjunto de la funcionalidad RAP, específicamente la protección del puntero de retorno. RAP en realidad se llama "Reuse Attack Protector", que está diseñado para proteger contra todas las formas de llamadas indirectas. El documento que vinculó describe algunas de las funciones de RAP, de las que forman parte la protección del puntero de retorno y las funciones de ICFG.
Podemos ver el siguiente ensamblaje en el documento:
push %rbx
mov 8(%rsp),%rbx
xor %r12,%rbx
...
xor %r12,%rbx
cmp %rbx,8(%rsp)
jnz .error
pop %rbx
retn
.error:
ud2
El primer bloque allí configura la cookie RAP:
; store the old value of rbx
push %rbx
; read the top value on the stack (the return pointer) and put it in rbx
mov 8(%rsp),%rbx
; xor rbx with a random value stored in r12
; rbx now contains the RAP canary
xor %r12,%rbx
Luego, al final de la función, antes de la ret:
; xor the RAP canary in rbx with the random value in r12
; this "decrypts" the stack pointer from the RAP canary
xor %r12,%rbx
; compare the top value on the stack (the return pointer)
; with the value decrypted from the RAP canary
cmp %rbx,8(%rsp)
; if the comparison fails, jump to error
jnz .error
; restore the original value of rbx
pop %rbx
; return
retn
.error:
; an error occured, quit the process
ud2
La idea detrás de ROP es que encontrará las instrucciones que desea (gadgets) seguidas de una instrucción de devolución. Esta función de protección reescribe las funciones para que la instrucción final antes de cada devolución sea siempre un pop %rbx
, y las instrucciones anteriores se usen para validar el canario RAP. Esto hace que sea realmente difícil encontrar gadgets ROP fuera de las instrucciones no alineadas (es decir, gadgets que simplemente existen debido a la interpretación binaria de instrucciones fuera de la alineación normal).
La protección se puede aplicar tanto a modo de usuario como a kernel. El valor de la cookie (el valor en% r12) se regenera por tarea, por syscall y por iteración en algunos bucles infinitos (por ejemplo, controladores de eventos y bucles de envío). El motivo de la última es que los bucles infinitos a menudo usan un ret
para salir del bucle. (esto no es del todo correcto).
EDITAR: Después de discutir esto más con Spender, sugeriré esperar a que salga la explicación. Hay mucha sutileza en cómo funciona la función y no estoy seguro de poder cubrirla con precisión en el documento y en mi breve discusión sobre el IRC. Una vez que esté listo, volveré a actualizar esta respuesta para darle una mejor idea de lo que hace.