* _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 <sys/socket.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include <module.h>
|
#include <module.h>
|
||||||
|
|
||||||
@ -24,7 +25,7 @@
|
|||||||
|
|
||||||
#define MAX_SOCKET_ADDRESS_LEN (sizeof(sockaddr_storage))
|
#define MAX_SOCKET_ADDRESS_LEN (sizeof(sockaddr_storage))
|
||||||
#define MAX_SOCKET_OPTION_LEN 128
|
#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;
|
static net_stack_interface_module_info* sStackInterface = NULL;
|
||||||
@ -112,7 +113,8 @@ prepare_userland_address_result(struct sockaddr* userAddress,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
prepare_userland_msghdr(const msghdr* userMessage, msghdr& message,
|
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)
|
if (userMessage == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@ -123,10 +125,18 @@ prepare_userland_msghdr(const msghdr* userMessage, msghdr& message,
|
|||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVecs = message.msg_iov;
|
||||||
|
userAddress = message.msg_name;
|
||||||
|
|
||||||
// copy iovecs from userland
|
// copy iovecs from userland
|
||||||
|
if (message.msg_iovlen < 0 || message.msg_iovlen > IOV_MAX)
|
||||||
|
return EMSGSIZE;
|
||||||
if (userVecs != NULL && message.msg_iovlen > 0) {
|
if (userVecs != NULL && message.msg_iovlen > 0) {
|
||||||
if (message.msg_iovlen > MAX_IO_VEC_COUNT || message.msg_iov == NULL)
|
iovec* vecs = (iovec*)malloc(sizeof(iovec) * message.msg_iovlen);
|
||||||
return B_BAD_VALUE;
|
if (vecs == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
vecsDeleter.SetTo(vecs);
|
||||||
|
|
||||||
if (!IS_USER_ADDRESS(message.msg_iov)
|
if (!IS_USER_ADDRESS(message.msg_iov)
|
||||||
|| user_memcpy(vecs, message.msg_iov,
|
|| user_memcpy(vecs, message.msg_iov,
|
||||||
message.msg_iovlen * sizeof(iovec)) != B_OK) {
|
message.msg_iovlen * sizeof(iovec)) != B_OK) {
|
||||||
@ -886,16 +896,35 @@ _user_recvmsg(int socket, struct msghdr *userMessage, int flags)
|
|||||||
{
|
{
|
||||||
// copy message from userland
|
// copy message from userland
|
||||||
msghdr message;
|
msghdr message;
|
||||||
iovec* userVecs = message.msg_iov;
|
iovec* userVecs;
|
||||||
iovec vecs[MAX_IO_VEC_COUNT];
|
MemoryDeleter vecsDeleter;
|
||||||
void* userAddress = message.msg_name;
|
void* userAddress;
|
||||||
char address[MAX_SOCKET_ADDRESS_LEN];
|
char address[MAX_SOCKET_ADDRESS_LEN];
|
||||||
|
|
||||||
status_t error = prepare_userland_msghdr(userMessage, message, userVecs,
|
status_t error = prepare_userland_msghdr(userMessage, message, userVecs,
|
||||||
vecs, userAddress, address);
|
vecsDeleter, userAddress, address);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
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()
|
// recvmsg()
|
||||||
SyscallRestartWrapper<ssize_t> result;
|
SyscallRestartWrapper<ssize_t> result;
|
||||||
|
|
||||||
@ -903,11 +932,16 @@ _user_recvmsg(int socket, struct msghdr *userMessage, int flags)
|
|||||||
if (result < (ssize_t)0)
|
if (result < (ssize_t)0)
|
||||||
return result;
|
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,
|
if (userAddress != NULL && user_memcpy(userAddress, address,
|
||||||
message.msg_namelen) != B_OK
|
message.msg_namelen) != B_OK
|
||||||
|| user_memcpy(&userMessage->msg_namelen, &message.msg_namelen,
|
|| userAncillary != NULL && user_memcpy(userAncillary, ancillary,
|
||||||
sizeof(message.msg_namelen)) != B_OK) {
|
message.msg_controllen) != B_OK
|
||||||
|
|| user_memcpy(userMessage, &message, sizeof(msghdr)) != B_OK) {
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,13 +988,13 @@ _user_sendmsg(int socket, const struct msghdr *userMessage, int flags)
|
|||||||
{
|
{
|
||||||
// copy message from userland
|
// copy message from userland
|
||||||
msghdr message;
|
msghdr message;
|
||||||
iovec* userVecs = message.msg_iov;
|
iovec* userVecs;
|
||||||
iovec vecs[MAX_IO_VEC_COUNT];
|
MemoryDeleter vecsDeleter;
|
||||||
void* userAddress = message.msg_name;
|
void* userAddress;
|
||||||
char address[MAX_SOCKET_ADDRESS_LEN];
|
char address[MAX_SOCKET_ADDRESS_LEN];
|
||||||
|
|
||||||
status_t error = prepare_userland_msghdr(userMessage, message, userVecs,
|
status_t error = prepare_userland_msghdr(userMessage, message, userVecs,
|
||||||
vecs, userAddress, address);
|
vecsDeleter, userAddress, address);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -970,6 +1004,28 @@ _user_sendmsg(int socket, const struct msghdr *userMessage, int flags)
|
|||||||
return B_BAD_ADDRESS;
|
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()
|
// sendmsg()
|
||||||
SyscallRestartWrapper<ssize_t> result;
|
SyscallRestartWrapper<ssize_t> result;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user