Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Sep 2017 04:29:57 +0000 (UTC)
From:      Maxim Sobolev <sobomax@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r323254 - head/sys/compat/freebsd32
Message-ID:  <201709070429.v874Tvom033960@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709070429.v874Tvom033960>