Просмотр исходного кода

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 неделя назад
Родитель
Сommit
15e0ca1072
1 измененных файлов с 9 добавлено и 0 удалено
  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
     return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
 #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;
 
     temp.r_msgtyp = msgtyp;
     temp.oldmsg = msgp;
     return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0);
+# endif
 #endif
 }
 ssize_t msgrcv (int msqid, void *msgp, size_t msgsz,