Este artículo explora un comportamiento peculiar y a menudo desconocido de /proc/self/mem en sistemas Linux: la capacidad de escribir en memoria marcada como inescrutable. Normalmente, el sistema operativo impide que el código escriba en áreas de memoria designadas como de solo lectura. Sin embargo, /proc/self/mem ofrece una vía para sortear estas restricciones, un comportamiento intencional y utilizado por herramientas como el compilador JIT de Julia y el depurador rr.
El truco radica en cómo /proc/self/mem funciona internamente. En lugar de intentar escribir directamente en la memoria protegida, el kernel utiliza una serie de funciones para mapear la página de memoria física a un espacio de direcciones del kernel donde sí se permite la escritura. El proceso implica varios pasos clave: primero, get_user_pages_remote() busca el marco de página física correspondiente a la dirección virtual de destino, ignorando las restricciones de escritura gracias a la bandera FOLL_FORCE. Luego, kmap() mapea ese marco físico al espacio de direcciones del kernel con permisos de escritura. Finalmente, copy_to_user_page() realiza la escritura real. Esta secuencia de eventos evita completamente la Unidad de Gestión de Memoria (MMU) y sus protecciones.
El código de ejemplo proporcionado demuestra este comportamiento escribiendo directamente en una página de memoria mapeada como de solo lectura y, aún más sorprendentemente, modificando el código ejecutable de la biblioteca libc (C standard library) insertando una instrucción de punto de interrupción (0xCC). La ejecución posterior de una función de libc (getchar) después de esta modificación resulta en una señal SIGTRAP, confirmando que la escritura fue exitosa.
Aunque este comportamiento puede parecer peligroso, es importante comprender que está controlado por el kernel y se utiliza en situaciones específicas donde se requiere la manipulación de memoria de bajo nivel. Sin embargo, es crucial tener en cuenta que este mecanismo puede ser explotado si no se utiliza con precaución. El artículo también menciona que, aunque el Write Protect bit (CR0.WP) está habilitado por defecto, el kernel puede manejar las fallas de página resultantes, lo que no representa una restricción real. En resumen, /proc/self/mem proporciona una herramienta poderosa para interactuar con la memoria del sistema, pero requiere una comprensión profunda de su funcionamiento interno y sus implicaciones de seguridad.
