No se puede mapear después de cambiar al modo de 64 bits en un proceso de espacio de usuario de Linux que se inició como 32 bits.
Intenté hacer una llamada al sistema mmap
después de cambiar al modo de 64 bits en Linux x86 (versión de Linux 5.15.6), pero la llamada al sistema devuelve ENOMEM
. Un ejemplo mínimo y reproducible se muestra en el siguiente código en ensamblador:
.text
.global _start
_start:
.code32
jmp $0x33, $start64 // jmp a start64 y cambiar al modo de 64 bits
.code64
start64:
mov $9, %rax // mmap
mov $0, %rdi // NULL
mov $0x1000, %rsi // tamaño
mov $1, %rdx // PROT_READ
mov $0x22, %r10
mov $0, %r8
mov $0, %r9
syscall
mov $60, %rax // salida estilo de 64 bits
mov $0, %rdi
syscall
La salida correspondiente de strace
es:
code
execve("./mmap_test32", ["./mmap_test32"], 0x7ffe0ccd7920 /* 60 vars */) = 0
mmap(NULL, 4096, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = -1 ENOMEM (No se puede asignar memoria)
exit(0) = ?
+++ exited with 0 +++
¿Alguien tiene idea de por qué esto no funciona?
davy.ai
El problema es que el código está cambiando al modo de 64 bits pero aún utiliza registros de 32 bits en la llamada al sistema
mmap
. Específicamente, la instrucciónmov $0x22, %r10
intenta establecer el parámetroflags
(quinto parámetro) de la llamada al sistemammap
, pero%r10
es un registro de 64 bits y no se establece correctamente la bandera de 32 bitsMAP_PRIVATE|MAP_ANONYMOUS
.Para solucionar esto, cambie la instrucción
mov $0x22, %r10
amov $0x22, %r10w
para que solo se establezcan los 16 bits inferiores de%r10
. Esto establecerá correctamente el parámetroflags
enMAP_PRIVATE|MAP_ANONYMOUS
.El código de ensamblador corregido sería: