diff --git a/headers/private/kernel/util/iovec_support.h b/headers/private/kernel/util/iovec_support.h new file mode 100644 index 0000000000..9482d10af5 --- /dev/null +++ b/headers/private/kernel/util/iovec_support.h @@ -0,0 +1,41 @@ +/* + * Copyright 2022, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + */ +#ifndef _UTIL_IOVEC_SUPPORT_H +#define _UTIL_IOVEC_SUPPORT_H + + +#include + + +static inline status_t +get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec*& vecs, + bool permitNull = false) +{ + // prevent integer overflow + if (vecCount > IOV_MAX) + return B_BAD_VALUE; + + if (!IS_USER_ADDRESS(userVecs)) + return B_BAD_ADDRESS; + + vecs = (iovec*)malloc(sizeof(iovec) * vecCount); + if (vecs == NULL) + return B_NO_MEMORY; + + if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) + return B_BAD_ADDRESS; + + for (size_t i = 0; i < vecCount; i++) { + if (permitNull && vecs[i].iov_base == NULL) + continue; + if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) + return B_BAD_ADDRESS; + } + + return B_OK; +} + + +#endif // _UTIL_IOVEC_SUPPORT_H diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp index 905414ff5b..7f528563b0 100644 --- a/src/system/kernel/fs/fd.cpp +++ b/src/system/kernel/fs/fd.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -785,15 +786,14 @@ static ssize_t common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count, bool write) { - if (!IS_USER_ADDRESS(userVecs)) - return B_BAD_ADDRESS; - if (pos < -1) return B_BAD_VALUE; - // prevent integer overflow exploit in malloc() - if (count > IOV_MAX) - return B_BAD_VALUE; + iovec* vecs; + status_t error = get_iovecs_from_user(userVecs, count, vecs, true); + if (error != B_OK) + return error; + MemoryDeleter _(vecs); FDGetter fdGetter; struct file_descriptor* descriptor = fdGetter.SetTo(fd, false); @@ -805,14 +805,6 @@ common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count, return B_FILE_ERROR; } - iovec* vecs = (iovec*)malloc(sizeof(iovec) * count); - if (vecs == NULL) - return B_NO_MEMORY; - MemoryDeleter _(vecs); - - if (user_memcpy(vecs, userVecs, sizeof(iovec) * count) != B_OK) - return B_BAD_ADDRESS; - bool movePosition = false; if (pos == -1) { pos = descriptor->pos; @@ -830,12 +822,6 @@ common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count, for (uint32 i = 0; i < count; i++) { if (vecs[i].iov_base == NULL) continue; - if (!IS_USER_ADDRESS(vecs[i].iov_base)) { - status = B_BAD_ADDRESS; - if (bytesTransferred == 0) - return status; - break; - } size_t length = vecs[i].iov_len; if (write) { diff --git a/src/system/kernel/fs/socket.cpp b/src/system/kernel/fs/socket.cpp index f234e92f93..a587eaa403 100644 --- a/src/system/kernel/fs/socket.cpp +++ b/src/system/kernel/fs/socket.cpp @@ -1,7 +1,6 @@ /* * Copyright 2009-2010, Axel Dörfler, axeld@pinc-software.de. * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. - * * Distributed under the terms of the MIT License. */ @@ -22,6 +21,7 @@ #include #include #include +#include #include #include @@ -161,22 +161,11 @@ prepare_userland_msghdr(const msghdr* userMessage, msghdr& message, if (message.msg_iovlen < 0 || message.msg_iovlen > IOV_MAX) return EMSGSIZE; if (userVecs != NULL && message.msg_iovlen > 0) { - iovec* vecs = (iovec*)malloc(sizeof(iovec) * message.msg_iovlen); - if (vecs == NULL) - return B_NO_MEMORY; + iovec* vecs; + status_t error = get_iovecs_from_user(message.msg_iov, message.msg_iovlen, vecs); + if (error != B_OK) + return error; vecsDeleter.SetTo(vecs); - - if (!IS_USER_ADDRESS(message.msg_iov) - || user_memcpy(vecs, message.msg_iov, - message.msg_iovlen * sizeof(iovec)) != B_OK) { - return B_BAD_ADDRESS; - } - - for (int i = 0; i < message.msg_iovlen; i++) { - if (!IS_USER_ADDRESS(vecs[i].iov_base)) - return B_BAD_ADDRESS; - } - message.msg_iov = vecs; } else { message.msg_iov = NULL; diff --git a/src/system/kernel/port.cpp b/src/system/kernel/port.cpp index 8e6d65cfd8..cacc36a330 100644 --- a/src/system/kernel/port.cpp +++ b/src/system/kernel/port.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -1923,15 +1924,10 @@ _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs, return B_BAD_ADDRESS; iovec *vecs = NULL; - if (userVecs && vecCount != 0) { - vecs = (iovec*)malloc(sizeof(iovec) * vecCount); - if (vecs == NULL) - return B_NO_MEMORY; - - if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) { - free(vecs); - return B_BAD_ADDRESS; - } + if (userVecs != NULL && vecCount != 0) { + status_t status = get_iovecs_from_user(userVecs, vecCount, vecs); + if (status != B_OK) + return status; } status_t status = writev_port_etc(port, messageCode, vecs, vecCount,