kernel: Use BStackOrHeapArray in fd & port vector I/O syscalls.
The socket syscall needs to still use the heap. Also add a comment around get_iovecs_from_user() indicating what callers must do.
This commit is contained in:
@@ -41,36 +41,31 @@ generic_memcpy(generic_addr_t dest, bool destPhysical, generic_addr_t src, bool
|
|||||||
|
|
||||||
#ifdef IS_USER_ADDRESS
|
#ifdef IS_USER_ADDRESS
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies an array of `iovec`s from userland.
|
||||||
|
* Callers must verify vecCount <= IOV_MAX and supply their own vecs buffer.
|
||||||
|
*/
|
||||||
static inline status_t
|
static inline status_t
|
||||||
get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec*& vecs,
|
get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec* vecs,
|
||||||
bool permitNull = false)
|
bool permitNull = false)
|
||||||
{
|
{
|
||||||
// prevent integer overflow
|
if (vecCount == 0)
|
||||||
if (vecCount > IOV_MAX || vecCount == 0)
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (!IS_USER_ADDRESS(userVecs))
|
if (!IS_USER_ADDRESS(userVecs))
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
|
if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK)
|
||||||
if (vecs == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) {
|
|
||||||
free(vecs);
|
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
|
||||||
|
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
for (size_t i = 0; i < vecCount; i++) {
|
for (size_t i = 0; i < vecCount; i++) {
|
||||||
if (permitNull && vecs[i].iov_base == NULL)
|
if (permitNull && vecs[i].iov_base == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) {
|
if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) {
|
||||||
free(vecs);
|
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) {
|
if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) {
|
||||||
free(vecs);
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
total += vecs[i].iov_len;
|
total += vecs[i].iov_len;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
#include <AutoDeleterDrivers.h>
|
#include <AutoDeleterDrivers.h>
|
||||||
#include <BytePointer.h>
|
#include <BytePointer.h>
|
||||||
|
#include <StackOrHeapArray.h>
|
||||||
|
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
#include <syscall_restart.h>
|
#include <syscall_restart.h>
|
||||||
@@ -759,12 +760,16 @@ common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count,
|
|||||||
{
|
{
|
||||||
if (pos < -1)
|
if (pos < -1)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
if (count > IOV_MAX)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
BStackOrHeapArray<iovec, 16> vecs(count);
|
||||||
|
if (!vecs.IsValid())
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
iovec* vecs;
|
|
||||||
status_t error = get_iovecs_from_user(userVecs, count, vecs, true);
|
status_t error = get_iovecs_from_user(userVecs, count, vecs, true);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
MemoryDeleter _(vecs);
|
|
||||||
|
|
||||||
FileDescriptorPutter descriptor(get_fd(get_current_io_context(false), fd));
|
FileDescriptorPutter descriptor(get_fd(get_current_io_context(false), fd));
|
||||||
if (!descriptor.IsSet())
|
if (!descriptor.IsSet())
|
||||||
|
|||||||
@@ -164,11 +164,14 @@ prepare_userland_msghdr(const msghdr* userMessage, msghdr& message,
|
|||||||
if (message.msg_iovlen < 0 || message.msg_iovlen > IOV_MAX)
|
if (message.msg_iovlen < 0 || message.msg_iovlen > IOV_MAX)
|
||||||
return EMSGSIZE;
|
return EMSGSIZE;
|
||||||
if (userVecs != NULL && message.msg_iovlen > 0) {
|
if (userVecs != NULL && message.msg_iovlen > 0) {
|
||||||
iovec* vecs;
|
iovec* vecs = (iovec*)malloc(sizeof(iovec) * message.msg_iovlen);
|
||||||
|
if (vecs == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
vecsDeleter.SetTo(vecs);
|
||||||
|
|
||||||
status_t error = get_iovecs_from_user(message.msg_iov, message.msg_iovlen, vecs);
|
status_t error = get_iovecs_from_user(message.msg_iov, message.msg_iovlen, vecs);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
vecsDeleter.SetTo(vecs);
|
|
||||||
message.msg_iov = vecs;
|
message.msg_iov = vecs;
|
||||||
} else {
|
} else {
|
||||||
message.msg_iov = NULL;
|
message.msg_iov = NULL;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
#include <StackOrHeapArray.h>
|
||||||
|
|
||||||
#include <arch/int.h>
|
#include <arch/int.h>
|
||||||
#include <heap.h>
|
#include <heap.h>
|
||||||
@@ -1920,10 +1921,13 @@ _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
|
|||||||
|
|
||||||
if (userVecs == NULL && bufferSize != 0)
|
if (userVecs == NULL && bufferSize != 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
|
if (vecCount > IOV_MAX)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
BStackOrHeapArray<iovec, 16> vecs(vecCount);
|
||||||
|
if (!vecs.IsValid())
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
iovec *vecs = NULL;
|
|
||||||
if (userVecs != NULL && vecCount != 0) {
|
if (userVecs != NULL && vecCount != 0) {
|
||||||
status_t status = get_iovecs_from_user(userVecs, vecCount, vecs);
|
status_t status = get_iovecs_from_user(userVecs, vecCount, vecs);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
@@ -1934,7 +1938,6 @@ _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
|
|||||||
bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
|
bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
|
||||||
timeout);
|
timeout);
|
||||||
|
|
||||||
free(vecs);
|
|
||||||
return syscall_restart_handle_timeout_post(status, timeout);
|
return syscall_restart_handle_timeout_post(status, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user