Clamp number of vectors to IOV_MAX / UIO_MAXIOV for GOutputStream writev() calls in the implementations

More vectors will give an error and we can simply clamp here and
consider it like a short write instead.

In case of GSocketOutputStream this is done here instead of inside
GSocket before calling sendmsg() because we we can't generically handle
short writes when sending messages on a socket, e.g. for datagram
sockets this causes only part of the datagram to be sent and an error
would be more useful in this case than sending corrupted data.

Also reduce the fallback limit to 16 in gsocket.c as that's the minimum
value required by POSIX and add a static assertion that the limit is
never bigger than G_MAXINT as that's the type recvmmsg/sendmmsg take.
This commit is contained in:
Sebastian Dröge 2019-05-29 16:04:55 +03:00
parent 57a1d79361
commit 20a2c379c4
5 changed files with 47 additions and 32 deletions

View File

@ -35,6 +35,23 @@ gboolean g_output_stream_async_close_is_via_threads (GOutputStream *stream);
void g_socket_connection_set_cached_remote_address (GSocketConnection *connection,
GSocketAddress *address);
/* POSIX defines IOV_MAX/UIO_MAXIOV as the maximum number of iovecs that can
* be sent in one go. We define our own version of it here as there are two
* possible names, and also define a fall-back value if none of the constants
* are defined */
#if defined(IOV_MAX)
#define G_IOV_MAX IOV_MAX
#elif defined(UIO_MAXIOV)
#define G_IOV_MAX UIO_MAXIOV
#else
/* 16 is the minimum value required by POSIX */
#define G_IOV_MAX 16
#endif
/* The various functions taking iovecs as parameter use a plain int
* for the number of vectors. Limit it to G_MAXINT for this reason.
*/
G_STATIC_ASSERT (G_IOV_MAX <= G_MAXINT);
G_END_DECLS

View File

@ -42,6 +42,7 @@
#endif
#include "glib-private.h"
#include "gioprivate.h"
#ifdef G_OS_WIN32
#include <io.h>
@ -243,11 +244,11 @@ g_local_file_output_stream_writev (GOutputStream *stream,
if (bytes_written)
*bytes_written = 0;
/* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
* We handle this like a short write in this case
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (n_vectors > G_MAXINT)
n_vectors = G_MAXINT;
if (n_vectors > G_IOV_MAX)
n_vectors = G_IOV_MAX;
file = G_LOCAL_FILE_OUTPUT_STREAM (stream);

View File

@ -74,6 +74,7 @@
#include "gcredentials.h"
#include "gcredentialsprivate.h"
#include "glibintl.h"
#include "gioprivate.h"
#ifdef G_OS_WIN32
/* For Windows XP runtime compatibility, but use the system's if_nametoindex() if available */
@ -4960,14 +4961,11 @@ g_socket_send_messages_with_timeout (GSocket *socket,
struct mmsghdr *msgvec;
gint i, num_sent;
#ifdef UIO_MAXIOV
#define MAX_NUM_MESSAGES UIO_MAXIOV
#else
#define MAX_NUM_MESSAGES 1024
#endif
if (num_messages > MAX_NUM_MESSAGES)
num_messages = MAX_NUM_MESSAGES;
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (num_messages > G_IOV_MAX)
num_messages = G_IOV_MAX;
msgvec = g_newa (struct mmsghdr, num_messages);
@ -5482,14 +5480,11 @@ g_socket_receive_messages_with_timeout (GSocket *socket,
struct mmsghdr *msgvec;
guint i, num_received;
#ifdef UIO_MAXIOV
#define MAX_NUM_MESSAGES UIO_MAXIOV
#else
#define MAX_NUM_MESSAGES 1024
#endif
if (num_messages > MAX_NUM_MESSAGES)
num_messages = MAX_NUM_MESSAGES;
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (num_messages > G_IOV_MAX)
num_messages = G_IOV_MAX;
msgvec = g_newa (struct mmsghdr, num_messages);

View File

@ -33,6 +33,7 @@
#include "gioerror.h"
#include "glibintl.h"
#include "gfiledescriptorbased.h"
#include "gioprivate.h"
struct _GSocketOutputStreamPrivate
{
@ -146,8 +147,8 @@ g_socket_output_stream_writev (GOutputStream *stream,
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (n_vectors > G_MAXINT)
n_vectors = G_MAXINT;
if (n_vectors > G_IOV_MAX)
n_vectors = G_IOV_MAX;
res = g_socket_send_message_with_timeout (output_stream->priv->socket, NULL,
vectors, n_vectors,
@ -194,8 +195,8 @@ g_socket_output_stream_pollable_writev_nonblocking (GPollableOutputStream *poll
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (n_vectors > G_MAXINT)
n_vectors = G_MAXINT;
if (n_vectors > G_IOV_MAX)
n_vectors = G_IOV_MAX;
return g_socket_send_message_with_timeout (output_stream->priv->socket,
NULL, vectors, n_vectors,

View File

@ -37,6 +37,7 @@
#include "gasynchelper.h"
#include "gfiledescriptorbased.h"
#include "glibintl.h"
#include "gioprivate.h"
/**
@ -425,11 +426,11 @@ g_unix_output_stream_writev (GOutputStream *stream,
if (bytes_written)
*bytes_written = 0;
/* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
* We handle this like a short write in this case
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (n_vectors > G_MAXINT)
n_vectors = G_MAXINT;
if (n_vectors > G_IOV_MAX)
n_vectors = G_IOV_MAX;
unix_stream = G_UNIX_OUTPUT_STREAM (stream);
@ -635,11 +636,11 @@ g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream
return G_POLLABLE_RETURN_WOULD_BLOCK;
}
/* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
* We handle this like a short write in this case
/* Clamp the number of vectors if more given than we can write in one go.
* The caller has to handle short writes anyway.
*/
if (n_vectors > G_MAXINT)
n_vectors = G_MAXINT;
if (n_vectors > G_IOV_MAX)
n_vectors = G_IOV_MAX;
if (G_OUTPUT_VECTOR_IS_IOVEC)
{