Jelajahi Sumber

sparc64: pass msgp and msgtyp to ipc() directly

msgrcv() returns the right length on sparc64 but leaves the caller's
buffer untouched: a probe that sends "hallo-msgq" and receives it back
prints ret=11 mtype=0 text="".

Same cause as the semctl case: sys_sparc_ipc() in
arch/sparc/kernel/sys_sparc_64.c hands ptr and fifth straight to
sys_msgrcv(),

	err = sys_msgrcv(first, ptr, (size_t)second, fifth, (int)third);

while the generic sys_ipc() expects the old ipc_kludge struct behind ptr
and reads msgp and msgtyp out of it with copy_from_user().  uClibc-ng
always builds that struct, so on sparc64 the kernel delivers the message
into those 16 bytes of stack and takes msgtyp from fifth, which we set to
zero.

glibc has the same two overrides for exactly this architecture,
SEMCTL_ARG_ADDRESS and MSGRCV_ARGS in
sysdeps/unix/sysv/linux/sparc/sparc64/ipc_priv.h -- the only place in
its tree that overrides either.

Reachable only when built against headers without __NR_msgrcv, i.e.
before 5.1, since sparc has no direct IPC calls at all there.

Verified A/B under qemu-system-sparc64 with 4.19.56 headers: before,
mtype=0 and an empty text; after, mtype=1 and "hallo-msgq".

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
ramin 1 Minggu lalu
induk
melakukan
15e0ca1072
1 mengubah file dengan 9 tambahan dan 0 penghapusan
  1. 9 0
      libc/misc/sysvipc/msgq.c

+ 9 - 0
libc/misc/sysvipc/msgq.c

@@ -75,11 +75,20 @@ static inline ssize_t do_msgrcv (int msqid, void *msgp, size_t msgsz,
 #ifdef __NR_msgrcv
 #ifdef __NR_msgrcv
     return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
     return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
 #else
 #else
+# if defined __sparc__ && defined __arch64__
+    /* sys_sparc_ipc() passes ptr and fifth straight to sys_msgrcv(), where the
+       generic sys_ipc() expects the ipc_kludge struct below and reads msgp and
+       msgtyp out of it.  Handing it &temp there makes the kernel deliver the
+       message into that 16-byte struct instead of the caller's buffer.  */
+    return __syscall_ipc(IPCOP_msgrcv, msqid, msgsz, msgflg, msgp,
+			 (void *) msgtyp);
+# else
     struct new_msg_buf temp;
     struct new_msg_buf temp;
 
 
     temp.r_msgtyp = msgtyp;
     temp.r_msgtyp = msgtyp;
     temp.oldmsg = msgp;
     temp.oldmsg = msgp;
     return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0);
     return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0);
+# endif
 #endif
 #endif
 }
 }
 ssize_t msgrcv (int msqid, void *msgp, size_t msgsz,
 ssize_t msgrcv (int msqid, void *msgp, size_t msgsz,