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:
parent
a0b57b9baa
commit
737f6952da
|
@ -107,7 +107,7 @@ union unix_sockaddr
|
|||
struct async_recv_ioctl
|
||||
{
|
||||
struct async_fileio io;
|
||||
WSABUF *control;
|
||||
void *control;
|
||||
struct WS_sockaddr *addr;
|
||||
int *addr_len;
|
||||
DWORD *ret_flags;
|
||||
|
@ -504,8 +504,62 @@ error:
|
|||
control->len = 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 */
|
||||
|
||||
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 )
|
||||
{
|
||||
#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;
|
||||
|
||||
#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||
if (async->control)
|
||||
{
|
||||
ERR( "Message control headers cannot be properly supported on this system.\n" );
|
||||
async->control->len = 0;
|
||||
if (in_wow64_call())
|
||||
{
|
||||
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
|
||||
* msg_namelen from recvmsg, but it does set msg_namelen to zero.
|
||||
|
|
Loading…
Reference in New Issue