* [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow @ 2020-10-23 15:13 Sergey Ostanevich 2020-10-23 20:06 ` Vladislav Shpilevoy ` (3 more replies) 0 siblings, 4 replies; 13+ messages in thread From: Sergey Ostanevich @ 2020-10-23 15:13 UTC (permalink / raw) To: tarantool-patches; +Cc: Vladislav Shpilevoy Static buffer overflow in thread local pool causes random fails on OSX platform. This was caused by an incorrect use of the allocator result: the snprintf returns the full size of the formatted string, rather the number of bytes written. Fixes #5312 Branch: https://github.com/tarantool/tarantool/tree/sergos/gh-5312-crash-in-libeio Issue: https://github.com/tarantool/tarantool/issues/5312 --- src/lib/core/sio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c index 97a512eee..44f952c7c 100644 --- a/src/lib/core/sio.c +++ b/src/lib/core/sio.c @@ -53,15 +53,15 @@ sio_socketname(int fd) int save_errno = errno; int name_size = 2 * SERVICE_NAME_MAXLEN; char *name = static_alloc(name_size); - int n = snprintf(name, name_size, "fd %d", fd); + int n = MIN(snprintf(name, name_size, "fd %d", fd), name_size); if (fd >= 0) { struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); if (rc == 0) { - n += snprintf(name + n, name_size - n, ", aka %s", + n += MIN(snprintf(name + n, name_size - n, ", aka %s", sio_strfaddr((struct sockaddr *)&addr, - addrlen)); + addrlen)), name_size - n); } addrlen = sizeof(addr); rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); -- 2.24.3 (Apple Git-128) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-10-23 15:13 [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow Sergey Ostanevich @ 2020-10-23 20:06 ` Vladislav Shpilevoy 2020-10-29 22:56 ` Vladislav Shpilevoy ` (2 subsequent siblings) 3 siblings, 0 replies; 13+ messages in thread From: Vladislav Shpilevoy @ 2020-10-23 20:06 UTC (permalink / raw) To: Sergey Ostanevich, tarantool-patches Hi! Thanks for the patch! It seems the patch fixes the bug. I don't have crashes anymore. LGTM. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-10-23 15:13 [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow Sergey Ostanevich 2020-10-23 20:06 ` Vladislav Shpilevoy @ 2020-10-29 22:56 ` Vladislav Shpilevoy 2020-10-30 7:07 ` Cyrill Gorcunov 2020-10-31 16:33 ` Vladislav Shpilevoy 2020-11-03 22:59 ` Vladislav Shpilevoy 3 siblings, 1 reply; 13+ messages in thread From: Vladislav Shpilevoy @ 2020-10-29 22:56 UTC (permalink / raw) To: Sergey Ostanevich, tarantool-patches, Kirill Yukhin If there won't be a second review in a few days, I will commit this. I can't properly run tests without this patch. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-10-29 22:56 ` Vladislav Shpilevoy @ 2020-10-30 7:07 ` Cyrill Gorcunov 0 siblings, 0 replies; 13+ messages in thread From: Cyrill Gorcunov @ 2020-10-30 7:07 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tml [-- Attachment #1: Type: text/plain, Size: 216 bytes --] Ack On Fri, Oct 30, 2020 at 1:56 AM Vladislav Shpilevoy < v.shpilevoy@tarantool.org> wrote: > If there won't be a second review in a few days, I will > commit this. I can't properly run tests without this patch. > [-- Attachment #2: Type: text/html, Size: 512 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-10-23 15:13 [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow Sergey Ostanevich 2020-10-23 20:06 ` Vladislav Shpilevoy 2020-10-29 22:56 ` Vladislav Shpilevoy @ 2020-10-31 16:33 ` Vladislav Shpilevoy 2020-11-02 13:19 ` Sergey Ostanevich 2020-11-03 22:59 ` Vladislav Shpilevoy 3 siblings, 1 reply; 13+ messages in thread From: Vladislav Shpilevoy @ 2020-10-31 16:33 UTC (permalink / raw) To: Sergey Ostanevich, tarantool-patches Hi! Thanks for the patch! On 23.10.2020 17:13, Sergey Ostanevich wrote: > Static buffer overflow in thread local pool causes random fails on OSX > platform. This was caused by an incorrect use of the allocator result: > the snprintf returns the full size of the formatted string, rather the > number of bytes written. > > Fixes #5312 > > Branch: https://github.com/tarantool/tarantool/tree/sergos/gh-5312-crash-in-libeio > Issue: https://github.com/tarantool/tarantool/issues/5312 > > --- > src/lib/core/sio.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c > index 97a512eee..44f952c7c 100644 > --- a/src/lib/core/sio.c > +++ b/src/lib/core/sio.c > @@ -53,15 +53,15 @@ sio_socketname(int fd) > int save_errno = errno; > int name_size = 2 * SERVICE_NAME_MAXLEN; > char *name = static_alloc(name_size); > - int n = snprintf(name, name_size, "fd %d", fd); > + int n = MIN(snprintf(name, name_size, "fd %d", fd), name_size); > if (fd >= 0) { > struct sockaddr_storage addr; > socklen_t addrlen = sizeof(addr); > int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); > if (rc == 0) { > - n += snprintf(name + n, name_size - n, ", aka %s", > + n += MIN(snprintf(name + n, name_size - n, ", aka %s", > sio_strfaddr((struct sockaddr *)&addr, > - addrlen)); > + addrlen)), name_size - n); After thinking more I realized it is not entirely correct. MIN(a, b) = ((a) < (b) ? (a) : (b)). It means, that either 'a' or 'b' is executed twice. If 'a' is the big snprintf above, it is also executed twice. So you can't really use MIN right away. I reworked the patch to use an existing macro - SNPRINT. See the new patch below and on the branch in a separate commit. I added a new function, because SNPRINT returns -1 in case of print function fail. ==================== diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c index 44f952c7c..d008526d5 100644 --- a/src/lib/core/sio.c +++ b/src/lib/core/sio.c @@ -46,6 +46,33 @@ static_assert(SMALL_STATIC_SIZE > NI_MAXHOST + NI_MAXSERV, "static buffer should fit host name"); +/** + * Safely print a socket description to the given buffer, with correct overflow + * checks and all. + */ +static int +sio_socketname_to_buffer(int fd, char *buf, int size) +{ + int n = 0; + SNPRINT(n, snprintf, buf, size, "fd %d", fd); + if (fd < 0) + return 0; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); + if (rc == 0) { + SNPRINT(n, snprintf, buf, size, ", aka %s", + sio_strfaddr((struct sockaddr *)&addr, addrlen)); + } + addrlen = sizeof(addr); + rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); + if (rc == 0) { + SNPRINT(n, snprintf, buf, size, ", peer of %s", + sio_strfaddr((struct sockaddr *)&addr, addrlen)); + } + return 0; +} + const char * sio_socketname(int fd) { @@ -53,25 +80,13 @@ sio_socketname(int fd) int save_errno = errno; int name_size = 2 * SERVICE_NAME_MAXLEN; char *name = static_alloc(name_size); - int n = MIN(snprintf(name, name_size, "fd %d", fd), name_size); - if (fd >= 0) { - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); - if (rc == 0) { - n += MIN(snprintf(name + n, name_size - n, ", aka %s", - sio_strfaddr((struct sockaddr *)&addr, - addrlen)), name_size - n); - } - addrlen = sizeof(addr); - rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); - if (rc == 0) { - n += snprintf(name + n, name_size - n, - ", peer of %s", - sio_strfaddr((struct sockaddr *)&addr, - addrlen)); - } - } + int rc = sio_socketname_to_buffer(fd, name, name_size); + /* + * Could fail only because of a bad format in snprintf, but it is not + * bad, so should not fail. + */ + assert(rc == 0); + (void)rc; /* * Restore the original errno, it might have been reset by * snprintf() or getsockname(). ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-10-31 16:33 ` Vladislav Shpilevoy @ 2020-11-02 13:19 ` Sergey Ostanevich 2020-11-02 21:09 ` Vladislav Shpilevoy 0 siblings, 1 reply; 13+ messages in thread From: Sergey Ostanevich @ 2020-11-02 13:19 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tarantool-patches Hi! Thanks for the investigation! My bad, I used MIN as a function with sematics of all agruments calculated before call. You're right - in case of define it can cause a double call. The SNPRINT although leaves some questions to me: in case 'written' is more or equal to 'size', it forces '_buf' to be set to NULL. But in the sio_socketname_to_buffer() there's no check for NULL between the calls. A call to snprintf() delivers a segfault, at least for Mac. Also, factoring out 18 loc out of a function with a total of 24 seems redundant - IMVHO. I prpose to explicitly get the result from snprintf and compare it to original limit. ====== --- a/src/lib/core/sio.c +++ b/src/lib/core/sio.c @@ -53,20 +53,22 @@ sio_socketname(int fd) int save_errno = errno; int name_size = 2 * SERVICE_NAME_MAXLEN; char *name = static_alloc(name_size); - int n = snprintf(name, name_size, "fd %d", fd); + int to_be_printed = snprintf(name, name_size, "fd %d", fd); + int n = MIN(to_be_printed, name_size); if (fd >= 0) { struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); if (rc == 0) { - n += snprintf(name + n, name_size - n, ", aka %s", + to_be_printed = snprintf(name + n, name_size - n, ", aka %s", sio_strfaddr((struct sockaddr *)&addr, addrlen)); + n += MIN(to_be_printed, name_size - n); } addrlen = sizeof(addr); rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); if (rc == 0) { - n += snprintf(name + n, name_size - n, + to_be_printed = snprintf(name + n, name_size - n, ", peer of %s", sio_strfaddr((struct sockaddr *)&addr, addrlen)); On 31 окт 17:33, Vladislav Shpilevoy wrote: > Hi! Thanks for the patch! > > On 23.10.2020 17:13, Sergey Ostanevich wrote: > > Static buffer overflow in thread local pool causes random fails on OSX > > platform. This was caused by an incorrect use of the allocator result: > > the snprintf returns the full size of the formatted string, rather the > > number of bytes written. > > > > Fixes #5312 > > > > Branch: https://github.com/tarantool/tarantool/tree/sergos/gh-5312-crash-in-libeio > > Issue: https://github.com/tarantool/tarantool/issues/5312 > > > > --- > > src/lib/core/sio.c | 6 +++--- > > 1 file changed, 3 insertions(+), 3 deletions(-) > > > > diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c > > index 97a512eee..44f952c7c 100644 > > --- a/src/lib/core/sio.c > > +++ b/src/lib/core/sio.c > > @@ -53,15 +53,15 @@ sio_socketname(int fd) > > int save_errno = errno; > > int name_size = 2 * SERVICE_NAME_MAXLEN; > > char *name = static_alloc(name_size); > > - int n = snprintf(name, name_size, "fd %d", fd); > > + int n = MIN(snprintf(name, name_size, "fd %d", fd), name_size); > > if (fd >= 0) { > > struct sockaddr_storage addr; > > socklen_t addrlen = sizeof(addr); > > int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); > > if (rc == 0) { > > - n += snprintf(name + n, name_size - n, ", aka %s", > > + n += MIN(snprintf(name + n, name_size - n, ", aka %s", > > sio_strfaddr((struct sockaddr *)&addr, > > - addrlen)); > > + addrlen)), name_size - n); > > After thinking more I realized it is not entirely correct. > MIN(a, b) = ((a) < (b) ? (a) : (b)). It means, that either > 'a' or 'b' is executed twice. If 'a' is the big snprintf above, > it is also executed twice. So you can't really use MIN right away. > > I reworked the patch to use an existing macro - SNPRINT. See the > new patch below and on the branch in a separate commit. > > I added a new function, because SNPRINT returns -1 in case of > print function fail. > > ==================== > diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c > index 44f952c7c..d008526d5 100644 > --- a/src/lib/core/sio.c > +++ b/src/lib/core/sio.c > @@ -46,6 +46,33 @@ > static_assert(SMALL_STATIC_SIZE > NI_MAXHOST + NI_MAXSERV, > "static buffer should fit host name"); > > +/** > + * Safely print a socket description to the given buffer, with correct overflow > + * checks and all. > + */ > +static int > +sio_socketname_to_buffer(int fd, char *buf, int size) > +{ > + int n = 0; > + SNPRINT(n, snprintf, buf, size, "fd %d", fd); > + if (fd < 0) > + return 0; > + struct sockaddr_storage addr; > + socklen_t addrlen = sizeof(addr); > + int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); > + if (rc == 0) { > + SNPRINT(n, snprintf, buf, size, ", aka %s", > + sio_strfaddr((struct sockaddr *)&addr, addrlen)); > + } > + addrlen = sizeof(addr); > + rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); > + if (rc == 0) { > + SNPRINT(n, snprintf, buf, size, ", peer of %s", > + sio_strfaddr((struct sockaddr *)&addr, addrlen)); > + } > + return 0; > +} > + > const char * > sio_socketname(int fd) > { > @@ -53,25 +80,13 @@ sio_socketname(int fd) > int save_errno = errno; > int name_size = 2 * SERVICE_NAME_MAXLEN; > char *name = static_alloc(name_size); > - int n = MIN(snprintf(name, name_size, "fd %d", fd), name_size); > - if (fd >= 0) { > - struct sockaddr_storage addr; > - socklen_t addrlen = sizeof(addr); > - int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); > - if (rc == 0) { > - n += MIN(snprintf(name + n, name_size - n, ", aka %s", > - sio_strfaddr((struct sockaddr *)&addr, > - addrlen)), name_size - n); > - } > - addrlen = sizeof(addr); > - rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); > - if (rc == 0) { > - n += snprintf(name + n, name_size - n, > - ", peer of %s", > - sio_strfaddr((struct sockaddr *)&addr, > - addrlen)); > - } > - } > + int rc = sio_socketname_to_buffer(fd, name, name_size); > + /* > + * Could fail only because of a bad format in snprintf, but it is not > + * bad, so should not fail. > + */ > + assert(rc == 0); > + (void)rc; > /* > * Restore the original errno, it might have been reset by > * snprintf() or getsockname(). ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-11-02 13:19 ` Sergey Ostanevich @ 2020-11-02 21:09 ` Vladislav Shpilevoy 2020-11-02 21:18 ` Cyrill Gorcunov 0 siblings, 1 reply; 13+ messages in thread From: Vladislav Shpilevoy @ 2020-11-02 21:09 UTC (permalink / raw) To: Sergey Ostanevich; +Cc: tarantool-patches > Thanks for the investigation! My bad, I used MIN as a function with > sematics of all agruments calculated before call. You're right - in case > of define it can cause a double call. > > The SNPRINT although leaves some questions to me: in case 'written' is > more or equal to 'size', it forces '_buf' to be set to NULL. But in the > sio_socketname_to_buffer() there's no check for NULL between the calls. > A call to snprintf() delivers a segfault, at least for Mac. Woops, SNPRINT is used a lot in the code. If it is true, we need to fix SNPRINT. > Also, factoring out 18 loc out of a function with a total of 24 seems > redundant - IMVHO. With your patch it is also an issue with alignment. See below. I tried to fix it in-place, but it was too ugly due to too big indentation. > --- a/src/lib/core/sio.c > +++ b/src/lib/core/sio.c > @@ -53,20 +53,22 @@ sio_socketname(int fd) > int save_errno = errno; > int name_size = 2 * SERVICE_NAME_MAXLEN; > char *name = static_alloc(name_size); > - int n = snprintf(name, name_size, "fd %d", fd); > + int to_be_printed = snprintf(name, name_size, "fd %d", fd); > + int n = MIN(to_be_printed, name_size); > if (fd >= 0) { > struct sockaddr_storage addr; > socklen_t addrlen = sizeof(addr); > int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); > if (rc == 0) { > - n += snprintf(name + n, name_size - n, ", aka %s", > + to_be_printed = snprintf(name + n, name_size - n, ", aka %s", > sio_strfaddr((struct sockaddr *)&addr, > addrlen)); Here sio_strfaddr( should get +17 spaces, and that makes it hard to read. So I extracted everything to a new function with lower indentation. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-11-02 21:09 ` Vladislav Shpilevoy @ 2020-11-02 21:18 ` Cyrill Gorcunov 2020-11-02 21:43 ` Vladislav Shpilevoy 0 siblings, 1 reply; 13+ messages in thread From: Cyrill Gorcunov @ 2020-11-02 21:18 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tarantool-patches On Mon, Nov 02, 2020 at 10:09:29PM +0100, Vladislav Shpilevoy wrote: > > Thanks for the investigation! My bad, I used MIN as a function with > > sematics of all agruments calculated before call. You're right - in case > > of define it can cause a double call. > > > > The SNPRINT although leaves some questions to me: in case 'written' is > > more or equal to 'size', it forces '_buf' to be set to NULL. But in the > > sio_socketname_to_buffer() there's no check for NULL between the calls. > > A call to snprintf() delivers a segfault, at least for Mac. > > Woops, SNPRINT is used a lot in the code. If it is true, we need to fix SNPRINT. Guys, I didn't follow the details of the series but thought of some helper like below. Will it help? --- From: Cyrill Gorcunov <gorcunov@gmail.com> Date: Sun, 1 Nov 2020 16:10:08 +0300 Subject: [PATCH] util: introduce scnprintf helper The misuse of snprintf is pretty common, lets provide scnprintf helper which is just a wrapper over vsnprintf with more sane return. Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- src/lib/core/util.c | 24 ++++++++++++++++++++++++ src/trivia/util.h | 3 +++ 2 files changed, 27 insertions(+) diff --git a/src/lib/core/util.c b/src/lib/core/util.c index dfce317f0..60e552174 100644 --- a/src/lib/core/util.c +++ b/src/lib/core/util.c @@ -84,6 +84,30 @@ strnindex(const char **haystack, const char *needle, uint32_t len, uint32_t hmax return hmax; } +/** + * scnprintf - Put formatted string into a buffer + * + * @param buf The destination buffer + * @param size The size of the buffer + * @param fmt The format string + * @param ... Arguments + * + * @return Number of chars written into \a buf without ending '\0'. + * @return 0 if \a size if 0. + */ +int +scnprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsnprintf(buf, size, fmt, args); + va_end(args); + + return i < (int)size ? i : ((size != 0) ? (int)size-1 : 0); +} + void close_all_xcpt(int fdc, ...) { diff --git a/src/trivia/util.h b/src/trivia/util.h index da5a3705e..cf2da15fc 100644 --- a/src/trivia/util.h +++ b/src/trivia/util.h @@ -98,6 +98,9 @@ strindex(const char **haystack, const char *needle, uint32_t hmax); uint32_t strnindex(const char **haystack, const char *needle, uint32_t len, uint32_t hmax); +int +scnprintf(char *buf, size_t size, const char *fmt, ...); + #define nelem(x) (sizeof((x))/sizeof((x)[0])) #define field_sizeof(compound_type, field) sizeof(((compound_type *)NULL)->field) #ifndef lengthof -- 2.26.2 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-11-02 21:18 ` Cyrill Gorcunov @ 2020-11-02 21:43 ` Vladislav Shpilevoy 2020-11-02 21:47 ` Cyrill Gorcunov 0 siblings, 1 reply; 13+ messages in thread From: Vladislav Shpilevoy @ 2020-11-02 21:43 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tarantool-patches On 02.11.2020 22:18, Cyrill Gorcunov wrote: > On Mon, Nov 02, 2020 at 10:09:29PM +0100, Vladislav Shpilevoy wrote: >>> Thanks for the investigation! My bad, I used MIN as a function with >>> sematics of all agruments calculated before call. You're right - in case >>> of define it can cause a double call. >>> >>> The SNPRINT although leaves some questions to me: in case 'written' is >>> more or equal to 'size', it forces '_buf' to be set to NULL. But in the >>> sio_socketname_to_buffer() there's no check for NULL between the calls. >>> A call to snprintf() delivers a segfault, at least for Mac. >> >> Woops, SNPRINT is used a lot in the code. If it is true, we need to fix SNPRINT. > > Guys, I didn't follow the details of the series but thought of some > helper like below. Will it help? In some places yes. But SNPRINT is used not only with snprintf. It also is used with vsnprintf, mp_snprint, vy_run_snprint_filename, tuple_snprint, say_format_plain_tail, json_escape, strftime, and probably more. So it would be better to fix SNPRINT. To cover all its usage cases. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-11-02 21:43 ` Vladislav Shpilevoy @ 2020-11-02 21:47 ` Cyrill Gorcunov 2020-11-03 13:59 ` Sergey Ostanevich 0 siblings, 1 reply; 13+ messages in thread From: Cyrill Gorcunov @ 2020-11-02 21:47 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tarantool-patches On Mon, Nov 02, 2020 at 10:43:02PM +0100, Vladislav Shpilevoy wrote: > > > > Guys, I didn't follow the details of the series but thought of some > > helper like below. Will it help? > > In some places yes. But SNPRINT is used not only with snprintf. > > It also is used with vsnprintf, mp_snprint, vy_run_snprint_filename, > tuple_snprint, say_format_plain_tail, json_escape, strftime, and probably > more. So it would be better to fix SNPRINT. To cover all its usage > cases. OK, sounds reasonable. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-11-02 21:47 ` Cyrill Gorcunov @ 2020-11-03 13:59 ` Sergey Ostanevich 2020-11-03 14:08 ` Cyrill Gorcunov 0 siblings, 1 reply; 13+ messages in thread From: Sergey Ostanevich @ 2020-11-03 13:59 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tarantool-patches, Vladislav Shpilevoy Hi! I double checked the snprintf fails only if buf is set to NULL _and_ the len is set to a non-zero value. So I would follow Vlad's proposal on factoring out the code to make it clearer. Sergos. ==== commit 6f6eb1b8f12679b69eba40ea960a9ebb439c798e Author: Sergey Ostanevich <sergos@tarantool.org> Date: Fri Oct 23 16:09:31 2020 +0300 core: fix static_alloc buffer overflow Static buffer overflow in thread local pool causes random fails on OSX platform. This was caused by an incorrect use of the allocator result. Fixes #5312 Co-authored-by: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c index 97a512eee..d008526d5 100644 --- a/src/lib/core/sio.c +++ b/src/lib/core/sio.c @@ -46,6 +46,33 @@ static_assert(SMALL_STATIC_SIZE > NI_MAXHOST + NI_MAXSERV, "static buffer should fit host name"); +/** + * Safely print a socket description to the given buffer, with correct overflow + * checks and all. + */ +static int +sio_socketname_to_buffer(int fd, char *buf, int size) +{ + int n = 0; + SNPRINT(n, snprintf, buf, size, "fd %d", fd); + if (fd < 0) + return 0; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); + if (rc == 0) { + SNPRINT(n, snprintf, buf, size, ", aka %s", + sio_strfaddr((struct sockaddr *)&addr, addrlen)); + } + addrlen = sizeof(addr); + rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); + if (rc == 0) { + SNPRINT(n, snprintf, buf, size, ", peer of %s", + sio_strfaddr((struct sockaddr *)&addr, addrlen)); + } + return 0; +} + const char * sio_socketname(int fd) { @@ -53,25 +80,13 @@ sio_socketname(int fd) int save_errno = errno; int name_size = 2 * SERVICE_NAME_MAXLEN; char *name = static_alloc(name_size); - int n = snprintf(name, name_size, "fd %d", fd); - if (fd >= 0) { - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - int rc = getsockname(fd, (struct sockaddr *) &addr, &addrlen); - if (rc == 0) { - n += snprintf(name + n, name_size - n, ", aka %s", - sio_strfaddr((struct sockaddr *)&addr, - addrlen)); - } - addrlen = sizeof(addr); - rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen); - if (rc == 0) { - n += snprintf(name + n, name_size - n, - ", peer of %s", - sio_strfaddr((struct sockaddr *)&addr, - addrlen)); - } - } + int rc = sio_socketname_to_buffer(fd, name, name_size); + /* + * Could fail only because of a bad format in snprintf, but it is not + * bad, so should not fail. + */ + assert(rc == 0); + (void)rc; /* * Restore the original errno, it might have been reset by * snprintf() or getsockname(). On 03 ноя 00:47, Cyrill Gorcunov wrote: > On Mon, Nov 02, 2020 at 10:43:02PM +0100, Vladislav Shpilevoy wrote: > > > > > > Guys, I didn't follow the details of the series but thought of some > > > helper like below. Will it help? > > > > In some places yes. But SNPRINT is used not only with snprintf. > > > > It also is used with vsnprintf, mp_snprint, vy_run_snprint_filename, > > tuple_snprint, say_format_plain_tail, json_escape, strftime, and probably > > more. So it would be better to fix SNPRINT. To cover all its usage > > cases. > > OK, sounds reasonable. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-11-03 13:59 ` Sergey Ostanevich @ 2020-11-03 14:08 ` Cyrill Gorcunov 0 siblings, 0 replies; 13+ messages in thread From: Cyrill Gorcunov @ 2020-11-03 14:08 UTC (permalink / raw) To: Sergey Ostanevich; +Cc: tarantool-patches, Vladislav Shpilevoy On Tue, Nov 03, 2020 at 04:59:42PM +0300, Sergey Ostanevich wrote: > Hi! > > I double checked the snprintf fails only if buf is set to NULL _and_ the > len is set to a non-zero value. > > So I would follow Vlad's proposal on factoring out the code to make it > clearer. > > Sergos. Looks ok to me. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow 2020-10-23 15:13 [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow Sergey Ostanevich ` (2 preceding siblings ...) 2020-10-31 16:33 ` Vladislav Shpilevoy @ 2020-11-03 22:59 ` Vladislav Shpilevoy 3 siblings, 0 replies; 13+ messages in thread From: Vladislav Shpilevoy @ 2020-11-03 22:59 UTC (permalink / raw) To: Sergey Ostanevich, tarantool-patches Pushed to 1.10, 2.5, 2.6, and master. ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2020-11-03 22:59 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-10-23 15:13 [Tarantool-patches] [PATCH] core: fix static_alloc buffer overflow Sergey Ostanevich 2020-10-23 20:06 ` Vladislav Shpilevoy 2020-10-29 22:56 ` Vladislav Shpilevoy 2020-10-30 7:07 ` Cyrill Gorcunov 2020-10-31 16:33 ` Vladislav Shpilevoy 2020-11-02 13:19 ` Sergey Ostanevich 2020-11-02 21:09 ` Vladislav Shpilevoy 2020-11-02 21:18 ` Cyrill Gorcunov 2020-11-02 21:43 ` Vladislav Shpilevoy 2020-11-02 21:47 ` Cyrill Gorcunov 2020-11-03 13:59 ` Sergey Ostanevich 2020-11-03 14:08 ` Cyrill Gorcunov 2020-11-03 22:59 ` Vladislav Shpilevoy
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox