Browse Source

libc: do not truncate the shmat address argument to int

shmat() fails with EFAULT on any 64-bit target that goes through the
ipc() multiplexer:

  shmat  ptr=0xffffffffffffffff errno=14

__syscall_ipc() takes third as long, and shmat passed "(int) &raddr" --
casting the address of a local to int, which drops the upper half on
LP64.  The kernel then does put_user(raddr, third) against a truncated
address and returns EFAULT before the caller ever sees a mapping.

In practice that is sparc64 built against pre-5.1 headers, the only
64-bit configuration left without a direct shmat syscall, but the cast
is wrong everywhere and the fix needs no architecture test.

The int return value in the same function is a separate, older wart:
retval only carries the error code on this path, the address comes back
through raddr, so it is harmless here and left alone.

Verified under qemu-system-sparc64 with 4.19.56 headers: shmat now
returns a usable mapping, the segment holds what is written to it and
shmdt succeeds; shm_nattch reads 1 while attached.

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
ramin 1 day ago
parent
commit
f7394293c3
1 changed files with 1 additions and 1 deletions
  1. 1 1
      libc/misc/sysvipc/shm.c

+ 1 - 1
libc/misc/sysvipc/shm.c

@@ -50,7 +50,7 @@ void * shmat (int shmid, const void *shmaddr, int shmflg)
     int retval;
     unsigned long raddr;
 
-    retval = __syscall_ipc(IPCOP_shmat, shmid, shmflg, (int) &raddr, (void *) shmaddr, 0);
+    retval = __syscall_ipc(IPCOP_shmat, shmid, shmflg, (long) &raddr, (void *) shmaddr, 0);
     return ((unsigned long int) retval > -(unsigned long int) SHMLBA
 	    ? (void *) retval : (void *) raddr);
 }