From 87e2ea351c7e754cc3df8f6c9c519aa9fd1559e2 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 21 Apr 2021 11:03:39 -0700 Subject: [PATCH] careadlinkat: avoid ptrdiff_t overflow * lib/careadlinkat.c: Include idx.h, minmax.h. (readlink_stk): Avoid ptrdiff_t overflow in object allocation. Since this module uses arbitrary allocators (including stdlib_allocator), it cannot assume GNU malloc semantics. * modules/careadlinkat (Depends-on): Add idx, minmax. --- ChangeLog | 7 +++++++ lib/careadlinkat.c | 28 +++++++++++----------------- modules/careadlinkat | 2 ++ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3aaee32bff..1e6cbd07f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2021-04-21 Paul Eggert + careadlinkat: avoid ptrdiff_t overflow + * lib/careadlinkat.c: Include idx.h, minmax.h. + (readlink_stk): Avoid ptrdiff_t overflow in object allocation. + Since this module uses arbitrary allocators (including + stdlib_allocator), it cannot assume GNU malloc semantics. + * modules/careadlinkat (Depends-on): Add idx, minmax. + execute-tests: pacify compiler * tests/test-execute-main.c (main): Use 0x7DEADBEE rather than 0xDEADBEEF for nonces, to avoid provoking AIX XLC compiler warning diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c index 18cfc114b6..d833a0bce0 100644 --- a/lib/careadlinkat.c +++ b/lib/careadlinkat.c @@ -22,6 +22,9 @@ #include "careadlinkat.h" +#include "idx.h" +#include "minmax.h" + #include #include #include @@ -65,11 +68,6 @@ readlink_stk (int fd, char const *filename, ssize_t (*preadlinkat) (int, char const *, char *, size_t), char stack_buf[STACK_BUF_SIZE]) { - char *buf; - size_t buf_size; - size_t buf_size_max = - SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; - if (! alloc) alloc = &stdlib_allocator; @@ -79,14 +77,14 @@ readlink_stk (int fd, char const *filename, buffer_size = STACK_BUF_SIZE; } - buf = buffer; - buf_size = buffer_size; + char *buf = buffer; + idx_t buf_size_max = MIN (IDX_MAX, MIN (SSIZE_MAX, SIZE_MAX)); + idx_t buf_size = MIN (buffer_size, buf_size_max); while (buf) { /* Attempt to read the link into the current buffer. */ - ssize_t link_length = preadlinkat (fd, filename, buf, buf_size); - size_t link_size; + idx_t link_length = preadlinkat (fd, filename, buf, buf_size); if (link_length < 0) { if (buf != buffer) @@ -98,7 +96,7 @@ readlink_stk (int fd, char const *filename, return NULL; } - link_size = link_length; + idx_t link_size = link_length; if (link_size < buf_size) { @@ -127,17 +125,13 @@ readlink_stk (int fd, char const *filename, if (buf != buffer) alloc->free (buf); - if (buf_size < buf_size_max / 2) - buf_size = 2 * buf_size + 1; - else if (buf_size < buf_size_max) - buf_size = buf_size_max; - else if (buf_size_max < SIZE_MAX) + if (buf_size_max / 2 <= buf_size) { errno = ENAMETOOLONG; return NULL; } - else - break; + + buf_size = 2 * buf_size + 1; buf = alloc->allocate (buf_size); } diff --git a/modules/careadlinkat b/modules/careadlinkat index 3f49aaecd7..b3375a9b20 100644 --- a/modules/careadlinkat +++ b/modules/careadlinkat @@ -7,6 +7,8 @@ lib/careadlinkat.h Depends-on: allocator +idx +minmax ssize_t unistd -- 2.39.5