From cf712371da839a8655506aacc2908f7ffc3988ab Mon Sep 17 00:00:00 2001 From: jmaloy Date: Thu, 13 Feb 2020 21:08:17 +0100 Subject: [PATCH 1/6] util: add slirp_fmt() helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-id: <20200213210818.9090-2-jmaloy@redhat.com> Patchwork-id: 93831 O-Subject: [RHEL-7.8 qemu-kvm PATCH 1/2] util: add slirp_fmt() helpers Bugzilla: 1800515 RH-Acked-by: Maxim Levitsky RH-Acked-by: Eduardo Habkost RH-Acked-by: Stefan Hajnoczi From: Marc-André Lureau Various calls to snprintf() in libslirp assume that snprintf() returns "only" the number of bytes written (excluding terminating NUL). https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04 "Upon successful completion, the snprintf() function shall return the number of bytes that would be written to s had n been sufficiently large excluding the terminating null byte." Introduce slirp_fmt() that handles several pathological cases the way libslirp usually expect: - treat error as fatal (instead of silently returning -1) - fmt0() will always \0 end - return the number of bytes actually written (instead of what would have been written, which would usually result in OOB later), including the ending \0 for fmt0() - warn if truncation happened (instead of ignoring) Other less common cases can still be handled with strcpy/snprintf() etc. Signed-off-by: Marc-André Lureau Reviewed-by: Samuel Thibault Message-Id: <20200127092414.169796-2-marcandre.lureau@redhat.com> Manually re-adapted from 30648c03b27fb8d9611b723184216cd3174b6775 since cerry-pick cannot be used here. There is no util.c file in this code version, so we add the two new functions as static functions in the file where they are going to be used. Signed-off-by: Jon Maloy Signed-off-by: Miroslav Rezanina --- slirp/tcp_subr.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 19e2245..e83575e 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -44,6 +44,9 @@ /* Don't do rfc1323 performance enhancements */ #define TCP_DO_RFC1323 0 +static int slirp_fmt(char *str, size_t size, const char *format, ...); +static int slirp_fmt0(char *str, size_t size, const char *format, ...); + /* * Tcp initialization */ @@ -935,3 +938,65 @@ int tcp_ctl(struct socket *so) sb->sb_wptr += sb->sb_cc; return 0; } + +static int slirp_vsnprintf(char *str, size_t size, + const char *format, va_list args) +{ + int rv = vsnprintf(str, size, format, args); + + if (rv < 0) { + g_error("vsnprintf() failed: %s", g_strerror(errno)); + } + + return rv; +} + +/* + * A snprintf()-like function that: + * - returns the number of bytes written (excluding optional \0-ending) + * - dies on error + * - warn on truncation + */ +static int slirp_fmt(char *str, size_t size, const char *format, ...) +{ + va_list args; + int rv; + + va_start(args, format); + rv = slirp_vsnprintf(str, size, format, args); + va_end(args); + + if (rv > size) { + g_critical("vsnprintf() truncation"); + } + + return MIN(rv, size); +} + +/* + * A snprintf()-like function that: + * - always \0-end (unless size == 0) + * - returns the number of bytes actually written, including \0 ending + * - dies on error + * - warn on truncation + */ +static int slirp_fmt0(char *str, size_t size, const char *format, ...) +{ + va_list args; + int rv; + + va_start(args, format); + rv = slirp_vsnprintf(str, size, format, args); + va_end(args); + + if (rv >= size) { + g_critical("vsnprintf() truncation"); + if (size > 0) + str[size - 1] = '\0'; + rv = size; + } else { + rv += 1; /* include \0 */ + } + + return rv; +} -- 1.8.3.1