freebsd32_sendmsg: fix control message ABI

When a freebsd32 caller uses all or most allowed space for control
messages (MCLBYTES == 2K) then the message may no longer fit when
the messages are padded for 64-bit alignment.  Historically we've just
shrugged and said there is no ABI guarantee.  We ran into this on
CheriBSD where a capsicumized 64-bit nm would fail when called with more
than 64 files.

Fix this by not gratutiously capping size of mbuf data we'll allocate
to MCLBYTES and let m_get2 allocate up to MJUMPAGESIZE (4K or larger).
Instead of hard-coding a length check, let m_get2 do it and check for a
NULL return.

Reviewed by:	markj, jhb, emaste
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D36322
This commit is contained in:
Brooks Davis 2022-08-24 18:34:39 +01:00
parent 9c3ad5ba93
commit c46697b9cb

View File

@ -1535,6 +1535,7 @@ freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
u_int msglen, outlen;
int error;
/* Enforce the size limit of the native implementation. */
if (buflen > MCLBYTES)
return (EINVAL);
@ -1570,20 +1571,20 @@ freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
outlen += CMSG_ALIGN(sizeof(*cm)) +
CMSG_ALIGN(msglen - FREEBSD32_ALIGN(sizeof(*cm)));
}
if (error == 0 && outlen > MCLBYTES) {
/*
* XXXMJ This implies that the upper limit on 32-bit aligned
* control messages is less than MCLBYTES, and so we are not
* perfectly compatible. However, there is no platform
* guarantee that mbuf clusters larger than MCLBYTES can be
* allocated.
*/
error = EINVAL;
}
if (error != 0)
goto out;
/*
* Allocate up to MJUMPAGESIZE space for the re-aligned and
* re-padded control messages. This allows a full MCLBYTES of
* 32-bit sized and aligned messages to fit and avoids an ABI
* mismatch with the native implementation.
*/
m = m_get2(outlen, M_WAITOK, MT_CONTROL, 0);
if (m == NULL) {
error = EINVAL;
goto out;
}
m->m_len = outlen;
md = mtod(m, void *);