Author: sobomax
Date: Thu Sep  7 04:29:57 2017
New Revision: 323254
URL: https://svnweb.freebsd.org/changeset/base/323254

Log:
  In the recvmsg32() system call iterate over returned structure(s)
  and convert any messages of types SCM_BINTIME, SCM_TIMESTAMP,
  SCM_REALTIME and SCM_MONOTONIC from 64-bit to its 32-bit
  representation. Otherwise we either run out of user-supplied
  buffer to copy those out resulting in the MSG_CTRUNC or simply
  return values that the userland 32-bit code is not going
  to parse correctly. This fixes at least two regression tests
  failing to function properly in 32-bit compat mode:
  
      tools/regression/sockets/udp_pingpong
      tools/regression/sockets/unix_cmsg
  
  PR:             kern/222039
  MFC after:    30 days

Modified:
  head/sys/compat/freebsd32/freebsd32.h
  head/sys/compat/freebsd32/freebsd32_misc.c

Modified: head/sys/compat/freebsd32/freebsd32.h
==============================================================================
--- head/sys/compat/freebsd32/freebsd32.h       Thu Sep  7 03:05:16 2017        
(r323253)
+++ head/sys/compat/freebsd32/freebsd32.h       Thu Sep  7 04:29:57 2017        
(r323254)
@@ -78,6 +78,15 @@ struct itimerspec32 {
        TS_CP((src), (dst), it_value);          \
 } while (0)
 
+struct bintime32 {
+       uint32_t sec;
+       uint32_t frac[2];
+};
+#define BT_CP(src, dst, fld) do {                              \
+       CP((src).fld, (dst).fld, sec);                          \
+       *(uint64_t *)&(dst).fld.frac[0] = (src).fld.frac;       \
+} while (0)
+
 struct rusage32 {
        struct timeval32 ru_utime;
        struct timeval32 ru_stime;

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c  Thu Sep  7 03:05:16 2017        
(r323253)
+++ head/sys/compat/freebsd32/freebsd32_misc.c  Thu Sep  7 04:29:57 2017        
(r323254)
@@ -113,6 +113,7 @@ FEATURE(compat_freebsd_32bit, "Compatible with 32-bit 
 CTASSERT(sizeof(struct timeval32) == 8);
 CTASSERT(sizeof(struct timespec32) == 8);
 CTASSERT(sizeof(struct itimerval32) == 16);
+CTASSERT(sizeof(struct bintime32) == 12);
 #endif
 CTASSERT(sizeof(struct statfs32) == 256);
 #ifdef __amd64__
@@ -1035,12 +1036,67 @@ freebsd32_copyoutmsghdr(struct msghdr *msg, struct msg
 
 #define        FREEBSD32_CMSG_DATA(cmsg)       ((unsigned char *)(cmsg) + \
                                 FREEBSD32_ALIGN(sizeof(struct cmsghdr)))
+
+static size_t
+freebsd32_cmsg_convert(struct cmsghdr *cm, void *data, socklen_t datalen)
+{
+       size_t copylen;
+       union {
+               struct timespec32 ts;
+               struct timeval32 tv;
+               struct bintime32 bt;
+       } tmp32;
+
+       union {
+               struct timespec ts;
+               struct timeval tv;
+               struct bintime bt;
+       } *in;
+
+       in = data;
+       copylen = 0;
+       switch (cm->cmsg_level) {
+       case SOL_SOCKET:
+               switch (cm->cmsg_type) {
+               case SCM_TIMESTAMP:
+                       TV_CP(*in, tmp32, tv);
+                       copylen = sizeof(tmp32.tv);
+                       break;
+
+               case SCM_BINTIME:
+                       BT_CP(*in, tmp32, bt);
+                       copylen = sizeof(tmp32.bt);
+                       break;
+
+               case SCM_REALTIME:
+               case SCM_MONOTONIC:
+                       TS_CP(*in, tmp32, ts);
+                       copylen = sizeof(tmp32.ts);
+                       break;
+
+               default:
+                       break;
+               }
+
+       default:
+               break;
+       }
+
+       if (copylen == 0)
+               return (datalen);
+
+       KASSERT((datalen >= copylen), ("corrupted cmsghdr"));
+
+       bcopy(&tmp32, data, copylen);
+       return (copylen);
+}
+
 static int
 freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control)
 {
        struct cmsghdr *cm;
        void *data;
-       socklen_t clen, datalen;
+       socklen_t clen, datalen, datalen_out;
        int error;
        caddr_t ctlbuf;
        int len, maxlen, copylen;
@@ -1064,16 +1120,16 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf
                            cm->cmsg_len > clen) {
                                error = EINVAL;
                                break;
-                       }       
+                       }
 
                        data   = CMSG_DATA(cm);
                        datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+                       datalen_out = freebsd32_cmsg_convert(cm, data, datalen);
 
                        /* Adjust message length */
                        cm->cmsg_len = FREEBSD32_ALIGN(sizeof(struct cmsghdr)) +
-                           datalen;
+                           datalen_out;
 
-
                        /* Copy cmsghdr */
                        copylen = sizeof(struct cmsghdr);
                        if (len < copylen) {
@@ -1081,7 +1137,7 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf
                                copylen = len;
                        }
 
-                       error = copyout(cm,ctlbuf,copylen);
+                       error = copyout(cm, ctlbuf, copylen);
                        if (error)
                                goto exit;
 
@@ -1092,13 +1148,13 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf
                                break;
 
                        /* Copy data */
-                       copylen = datalen;
+                       copylen = datalen_out;
                        if (len < copylen) {
                                msg->msg_flags |= MSG_CTRUNC;
                                copylen = len;
                        }
 
-                       error = copyout(data,ctlbuf,copylen);
+                       error = copyout(data, ctlbuf, copylen);
                        if (error)
                                goto exit;
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to