* _user_{send,recf}msg() no longer copy iovecs on the stack. They use
the heap and the IOV_MAX limit. * They also take the responsibility of copying the ancillary data in and out. * These syscalls were badly broken. They used a member of an uninitialized structure instead of the iovec pointer passed from userland. sendmsg() would thus fail or send arbitrary data, recvmsg() would overwrite arbitrary memory. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24939 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
9c6ab2ae36
commit
5f2d64a25e
@ -6,6 +6,7 @@
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <module.h>
|
||||
|
||||
@ -24,7 +25,7 @@
|
||||
|
||||
#define MAX_SOCKET_ADDRESS_LEN (sizeof(sockaddr_storage))
|
||||
#define MAX_SOCKET_OPTION_LEN 128
|
||||
#define MAX_IO_VEC_COUNT 128
|
||||
#define MAX_ANCILLARY_DATA_LEN 1024
|
||||
|
||||
|
||||
static net_stack_interface_module_info* sStackInterface = NULL;
|
||||
@ -112,7 +113,8 @@ prepare_userland_address_result(struct sockaddr* userAddress,
|
||||
|
||||
static status_t
|
||||
prepare_userland_msghdr(const msghdr* userMessage, msghdr& message,
|
||||
iovec*& userVecs, iovec* vecs, void*& userAddress, char* address)
|
||||
iovec*& userVecs, MemoryDeleter& vecsDeleter, void*& userAddress,
|
||||
char* address)
|
||||
{
|
||||
if (userMessage == NULL)
|
||||
return B_BAD_VALUE;
|
||||
@ -123,10 +125,18 @@ prepare_userland_msghdr(const msghdr* userMessage, msghdr& message,
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
userVecs = message.msg_iov;
|
||||
userAddress = message.msg_name;
|
||||
|
||||
// copy iovecs from userland
|
||||
if (message.msg_iovlen < 0 || message.msg_iovlen > IOV_MAX)
|
||||
return EMSGSIZE;
|
||||
if (userVecs != NULL && message.msg_iovlen > 0) {
|
||||
if (message.msg_iovlen > MAX_IO_VEC_COUNT || message.msg_iov == NULL)
|
||||
return B_BAD_VALUE;
|
||||
iovec* vecs = (iovec*)malloc(sizeof(iovec) * message.msg_iovlen);
|
||||
if (vecs == NULL)
|
||||
return B_NO_MEMORY;
|
||||
vecsDeleter.SetTo(vecs);
|
||||
|
||||
if (!IS_USER_ADDRESS(message.msg_iov)
|
||||
|| user_memcpy(vecs, message.msg_iov,
|
||||
message.msg_iovlen * sizeof(iovec)) != B_OK) {
|
||||
@ -886,16 +896,35 @@ _user_recvmsg(int socket, struct msghdr *userMessage, int flags)
|
||||
{
|
||||
// copy message from userland
|
||||
msghdr message;
|
||||
iovec* userVecs = message.msg_iov;
|
||||
iovec vecs[MAX_IO_VEC_COUNT];
|
||||
void* userAddress = message.msg_name;
|
||||
iovec* userVecs;
|
||||
MemoryDeleter vecsDeleter;
|
||||
void* userAddress;
|
||||
char address[MAX_SOCKET_ADDRESS_LEN];
|
||||
|
||||
status_t error = prepare_userland_msghdr(userMessage, message, userVecs,
|
||||
vecs, userAddress, address);
|
||||
vecsDeleter, userAddress, address);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// prepare a buffer for ancillary data
|
||||
MemoryDeleter ancillaryDeleter;
|
||||
void* ancillary = NULL;
|
||||
void* userAncillary = message.msg_control;
|
||||
if (userAncillary != NULL) {
|
||||
if (!IS_USER_ADDRESS(userAncillary))
|
||||
return B_BAD_ADDRESS;
|
||||
if (message.msg_controllen < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (message.msg_controllen > MAX_ANCILLARY_DATA_LEN)
|
||||
message.msg_controllen > MAX_ANCILLARY_DATA_LEN;
|
||||
|
||||
message.msg_control = ancillary = malloc(message.msg_controllen);
|
||||
if (message.msg_control == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
ancillaryDeleter.SetTo(ancillary);
|
||||
}
|
||||
|
||||
// recvmsg()
|
||||
SyscallRestartWrapper<ssize_t> result;
|
||||
|
||||
@ -903,11 +932,16 @@ _user_recvmsg(int socket, struct msghdr *userMessage, int flags)
|
||||
if (result < (ssize_t)0)
|
||||
return result;
|
||||
|
||||
// copy the address and address length back to userland
|
||||
// copy the address, the ancillary data, and the message header back to
|
||||
// userland
|
||||
message.msg_name = userAddress;
|
||||
message.msg_iov = userVecs;
|
||||
message.msg_control = userAncillary;
|
||||
if (userAddress != NULL && user_memcpy(userAddress, address,
|
||||
message.msg_namelen) != B_OK
|
||||
|| user_memcpy(&userMessage->msg_namelen, &message.msg_namelen,
|
||||
sizeof(message.msg_namelen)) != B_OK) {
|
||||
message.msg_namelen) != B_OK
|
||||
|| userAncillary != NULL && user_memcpy(userAncillary, ancillary,
|
||||
message.msg_controllen) != B_OK
|
||||
|| user_memcpy(userMessage, &message, sizeof(msghdr)) != B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
@ -954,13 +988,13 @@ _user_sendmsg(int socket, const struct msghdr *userMessage, int flags)
|
||||
{
|
||||
// copy message from userland
|
||||
msghdr message;
|
||||
iovec* userVecs = message.msg_iov;
|
||||
iovec vecs[MAX_IO_VEC_COUNT];
|
||||
void* userAddress = message.msg_name;
|
||||
iovec* userVecs;
|
||||
MemoryDeleter vecsDeleter;
|
||||
void* userAddress;
|
||||
char address[MAX_SOCKET_ADDRESS_LEN];
|
||||
|
||||
status_t error = prepare_userland_msghdr(userMessage, message, userVecs,
|
||||
vecs, userAddress, address);
|
||||
vecsDeleter, userAddress, address);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@ -970,6 +1004,28 @@ _user_sendmsg(int socket, const struct msghdr *userMessage, int flags)
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
// copy ancillary data from userland
|
||||
MemoryDeleter ancillaryDeleter;
|
||||
void* userAncillary = message.msg_control;
|
||||
if (userAncillary != NULL) {
|
||||
if (!IS_USER_ADDRESS(userAncillary))
|
||||
return B_BAD_ADDRESS;
|
||||
if (message.msg_controllen < 0
|
||||
|| message.msg_controllen > MAX_ANCILLARY_DATA_LEN) {
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
message.msg_control = malloc(message.msg_controllen);
|
||||
if (message.msg_control == NULL)
|
||||
return B_NO_MEMORY;
|
||||
ancillaryDeleter.SetTo(message.msg_control);
|
||||
|
||||
if (user_memcpy(message.msg_control, userAncillary,
|
||||
message.msg_controllen) != B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
// sendmsg()
|
||||
SyscallRestartWrapper<ssize_t> result;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user