svn commit: r323254 - head/sys/compat/freebsd32
Maxim Sobolev
sobomax at FreeBSD.org
Thu Sep 7 04:29:59 UTC 2017
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;
More information about the svn-src-head
mailing list