diff options
Diffstat (limited to 'io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch')
-rw-r--r-- | io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch b/io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch new file mode 100644 index 0000000..09767bd --- /dev/null +++ b/io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch @@ -0,0 +1,210 @@ +From 1836bb2ebf62bd9a3588f2ed2d851c8ae810097a Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella <adhemerval.zanella@linaro.org> +Date: Wed, 25 Aug 2021 11:17:06 -0300 +Subject: [PATCH] io: Fix ftw internal realloc buffer (BZ #28126) + +The 106ff08526d3ca did not take in consideration the buffer might be +reallocated if the total path is larger than PATH_MAX. The realloc +uses 'dirbuf', where 'dirstreams' is the allocated buffer. + +Checked on x86_64-linux-gnu. + +Reviewed-by: H.J. Lu <hjl.tools@gmail.com> +--- + io/Makefile | 1 + + io/ftw.c | 39 ++++++++++----------- + io/tst-ftw-bz28126.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 117 insertions(+), 20 deletions(-) + create mode 100644 io/tst-ftw-bz28126.c + +diff --git a/io/Makefile b/io/Makefile +index 9871ecb..ecf65ab 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -79,6 +79,7 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-futimens \ + tst-utimensat \ + tst-closefrom \ ++ tst-ftw-bz28126 + + tests-time64 := \ + tst-futimens-time64 \ +diff --git a/io/ftw.c b/io/ftw.c +index f0db173..fe95345 100644 +--- a/io/ftw.c ++++ b/io/ftw.c +@@ -203,6 +203,20 @@ struct ftw_data + void *known_objects; + }; + ++static bool ++ftw_allocate (struct ftw_data *data, size_t newsize) ++{ ++ void *newp = realloc (data->dirstreams, data->maxdir ++ * sizeof (struct dir_data *) ++ + newsize); ++ if (newp == NULL) ++ return false; ++ data->dirstreams = newp; ++ data->dirbufsize = newsize; ++ data->dirbuf = (char *) data->dirstreams ++ + data->maxdir * sizeof (struct dir_data *); ++ return true; ++} + + /* Internally we use the FTW_* constants used for `nftw'. When invoked + as `ftw', map each flag to the subset of values used by `ftw'. */ +@@ -388,17 +402,9 @@ process_entry (struct ftw_data *data, struct dir_data *dir, const char *name, + return 0; + + new_buflen = data->ftw.base + namlen + 2; +- if (data->dirbufsize < new_buflen) +- { +- /* Enlarge the buffer. */ +- char *newp; +- +- data->dirbufsize = 2 * new_buflen; +- newp = (char *) realloc (data->dirbuf, data->dirbufsize); +- if (newp == NULL) +- return -1; +- data->dirbuf = newp; +- } ++ if (data->dirbufsize < new_buflen ++ && !ftw_allocate (data, 2 * new_buflen)) ++ return -1; + + *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0'; + +@@ -628,7 +634,7 @@ __attribute ((noinline)) + ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, + int flags) + { +- struct ftw_data data; ++ struct ftw_data data = { .dirstreams = NULL }; + struct STRUCT_STAT st; + int result = 0; + int save_err; +@@ -646,16 +652,9 @@ ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, + data.maxdir = descriptors < 1 ? 1 : descriptors; + data.actdir = 0; + /* PATH_MAX is always defined when we get here. */ +- data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX); +- data.dirstreams = malloc (data.maxdir * sizeof (struct dir_data *) +- + data.dirbufsize); +- if (data.dirstreams == NULL) ++ if (!ftw_allocate (&data, MAX (2 * strlen (dir), PATH_MAX))) + return -1; +- + memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *)); +- +- data.dirbuf = (char *) data.dirstreams +- + data.maxdir * sizeof (struct dir_data *); + cp = __stpcpy (data.dirbuf, dir); + /* Strip trailing slashes. */ + while (cp > data.dirbuf + 1 && cp[-1] == '/') +diff --git a/io/tst-ftw-bz28126.c b/io/tst-ftw-bz28126.c +new file mode 100644 +index 0000000..94044ab +--- /dev/null ++++ b/io/tst-ftw-bz28126.c +@@ -0,0 +1,97 @@ ++/* Check if internal buffer reallocation work for large paths (BZ #28126) ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <ftw.h> ++#include <limits.h> ++#include <string.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <support/temp_file.h> ++#include <support/xunistd.h> ++#include <stdio.h> ++ ++static int ++my_func (const char *file, const struct stat *sb, int flag) ++{ ++ return 0; ++} ++ ++static const char folder[NAME_MAX] = { [0 ... 253] = 'a', [254] = '\0' }; ++ ++#define NSUBFOLDERS 16 ++static int nsubfolders; ++ ++static void ++do_cleanup (void) ++{ ++ xchdir (".."); ++ for (int i = 0; i < nsubfolders; i++) ++ { ++ remove (folder); ++ xchdir (".."); ++ } ++ remove (folder); ++} ++#define CLEANUP_HANDLER do_cleanup ++ ++static void ++check_mkdir (const char *path) ++{ ++ int r = mkdir (path, 0777); ++ /* Some filesystem such as overlayfs does not support larger path required ++ to trigger the internal buffer reallocation. */ ++ if (r != 0) ++ { ++ if (errno == ENAMETOOLONG) ++ FAIL_UNSUPPORTED ("the filesystem does not support the required" ++ "large path"); ++ else ++ FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", folder, 0777); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ char *tempdir = support_create_temp_directory ("tst-bz28126"); ++ ++ /* Create path with various subfolders to force an internal buffer ++ reallocation within ntfw. */ ++ char *path = xasprintf ("%s/%s", tempdir, folder); ++ check_mkdir (path); ++ xchdir (path); ++ free (path); ++ for (int i = 0; i < NSUBFOLDERS - 1; i++) ++ { ++ check_mkdir (folder); ++ xchdir (folder); ++ nsubfolders++; ++ } ++ ++ TEST_COMPARE (ftw (tempdir, my_func, 20), 0); ++ ++ free (tempdir); ++ ++ do_cleanup (); ++ ++ return 0; ++} ++ ++#include <support/test-driver.c> +-- +1.8.3.1 + |