ntdll: Handle WoW64 control message translation.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-12-10 11:27:34 -06:00 committed by Alexandre Julliard
parent a0b57b9baa
commit 737f6952da
1 changed files with 87 additions and 12 deletions

View File

@ -107,7 +107,7 @@ union unix_sockaddr
struct async_recv_ioctl struct async_recv_ioctl
{ {
struct async_fileio io; struct async_fileio io;
WSABUF *control; void *control;
struct WS_sockaddr *addr; struct WS_sockaddr *addr;
int *addr_len; int *addr_len;
DWORD *ret_flags; DWORD *ret_flags;
@ -504,8 +504,62 @@ error:
control->len = 0; control->len = 0;
return 0; return 0;
} }
#else
static int convert_control_headers(struct msghdr *hdr, WSABUF *control)
{
ERR( "Message control headers cannot be properly supported on this system.\n" );
control->len = 0;
return 0;
}
#endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
struct cmsghdr_32
{
ULONG cmsg_len;
INT cmsg_level;
INT cmsg_type;
/* UCHAR cmsg_data[]; */
};
static size_t cmsg_align_32( size_t len )
{
return (len + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1);
}
/* we assume that cmsg_data does not require translation, which is currently
* true for all messages */
static int wow64_translate_control( const WSABUF *control64, struct afd_wsabuf_32 *control32 )
{
char *const buf32 = ULongToPtr(control32->buf);
const ULONG max_len = control32->len;
const char *ptr64 = control64->buf;
char *ptr32 = buf32;
while (ptr64 < control64->buf + control64->len)
{
struct cmsghdr_32 *cmsg32 = (struct cmsghdr_32 *)ptr32;
const WSACMSGHDR *cmsg64 = (const WSACMSGHDR *)ptr64;
if (ptr32 + sizeof(*cmsg32) + cmsg_align_32( cmsg64->cmsg_len ) > buf32 + max_len)
{
control32->len = 0;
return 0;
}
cmsg32->cmsg_len = cmsg64->cmsg_len - sizeof(*cmsg64) + sizeof(*cmsg32);
cmsg32->cmsg_level = cmsg64->cmsg_level;
cmsg32->cmsg_type = cmsg64->cmsg_type;
memcpy( cmsg32 + 1, cmsg64 + 1, cmsg64->cmsg_len );
ptr64 += WSA_CMSG_ALIGN( cmsg64->cmsg_len );
ptr32 += cmsg_align_32( cmsg32->cmsg_len );
}
control32->len = ptr32 - buf32;
FIXME("-> %d\n", control32->len);
return 1;
}
static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *size ) static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *size )
{ {
#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
@ -543,20 +597,41 @@ static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *siz
status = (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; status = (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
if (async->control) if (async->control)
{ {
ERR( "Message control headers cannot be properly supported on this system.\n" ); if (in_wow64_call())
async->control->len = 0; {
char control_buffer64[512];
WSABUF wsabuf;
wsabuf.len = sizeof(control_buffer64);
wsabuf.buf = control_buffer64;
if (convert_control_headers( &hdr, &wsabuf ))
{
if (!wow64_translate_control( &wsabuf, async->control ))
{
WARN( "Application passed insufficient room for control headers.\n" );
*async->ret_flags |= WS_MSG_CTRUNC;
status = STATUS_BUFFER_OVERFLOW;
}
}
else
{
FIXME( "control buffer is too small\n" );
*async->ret_flags |= WS_MSG_CTRUNC;
status = STATUS_BUFFER_OVERFLOW;
}
}
else
{
if (!convert_control_headers( &hdr, async->control ))
{
WARN( "Application passed insufficient room for control headers.\n" );
*async->ret_flags |= WS_MSG_CTRUNC;
status = STATUS_BUFFER_OVERFLOW;
}
}
} }
#else
if (async->control && !convert_control_headers( &hdr, async->control ))
{
WARN( "Application passed insufficient room for control headers.\n" );
*async->ret_flags |= WS_MSG_CTRUNC;
status = STATUS_BUFFER_OVERFLOW;
}
#endif
/* If this socket is connected, Linux doesn't give us msg_name and /* If this socket is connected, Linux doesn't give us msg_name and
* msg_namelen from recvmsg, but it does set msg_namelen to zero. * msg_namelen from recvmsg, but it does set msg_namelen to zero.