logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 4036111e8cb961d05bc5aefa4e72b25739339874
parent 8ea6e9f38d660dcc920717b6944b85fa669d562f
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 28 Jun 2025 05:11:48 +0200

cmd/df: use reallocarray instead of hardcoding a maximum of 4096 devices

Diffstat:

Mcmd/df.c51++++++++++++++++++++++++++++++++++++++++++---------
Mconfigure4++--
2 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/cmd/df.c b/cmd/df.c @@ -2,9 +2,10 @@ // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> // SPDX-License-Identifier: MPL-2.0 -#define _POSIX_C_SOURCE 200809L +#define _POSIX_C_SOURCE 202405L #define _DEFAULT_SOURCE // mntent in glibc 2.19+ +#include "../lib/reallocarray.h" #include "../libutils/getopt_nolong.h" #include "../libutils/humanize.h" @@ -53,6 +54,7 @@ main(int argc, char *argv[]) { bool opt_P = false, opt_h = false, opt_a = false, opt_T = false, opt_l = false, opt_i = false; int fs_col_width = 20; + dev_t *devices = NULL; size_t excluded_count = 0; static char *excluded[DF_MNT_TYPE_MAX]; @@ -212,9 +214,25 @@ main(int argc, char *argv[]) goto error; } - // FIXME: Fix maximum number of mount entries / devices - dev_t devices[4096]; + // Linux has a configurable limit of maximum mounts which defaults to 100_000 + // See /proc/sys/fs/mount-max introduced in Linux 4.9 for CVE-2016-6213 + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d29216842a85c7970c536108e093963f02714498 + // + // Which is way too much to be either stack-allocated or statically allocated: + // 100000*sizeof(dev_t) = 100000*8 bytes ≈ 781.25 KiB + // So reallocarray to the rescue size_t devices_found = 0; + size_t devices_len = 100; + devices = reallocarray(NULL, devices_len, sizeof(dev_t)); + if(!devices) + { + fprintf(stderr, + "%s: error: Failed to allocate memory for storing (%zd) devices: %s\n", + argv0, + devices_len, + strerror(errno)); + goto error; + } // Even with argc>0 we still need to go over mntent for the filesystem mountpoint and type while(args_left > 0) @@ -305,10 +323,23 @@ main(int argc, char *argv[]) if(dupe) continue; - if(devices_found >= 4096) - fprintf(stderr, - "%s: warning: Reached maximum amount of devices which can be deduplicated\n", - argv0); + if(devices_found + 1 >= devices_len) + { + devices_len *= 2; + if(devices_len <= 0) abort(); + + devices = reallocarray(devices, devices_len, sizeof(dev_t)); + + if(!devices) + { + fprintf(stderr, + "%s: error: Failed to allocate memory for storing (%zd) devices: %s\n", + argv0, + devices_len, + strerror(errno)); + goto error; + } + } devices[devices_found++] = file_stats.st_dev; } @@ -431,12 +462,14 @@ main(int argc, char *argv[]) endmntent(mounted); - if(argc > 0) free(arg_devs); + free(devices); + free(arg_devs); return 0; error: - if(argc > 0) free(arg_devs); + free(devices); + free(arg_devs); return 1; } diff --git a/configure b/configure @@ -249,8 +249,8 @@ check_conftest configure.d/sendfile_linux.c && cpp_define HAS_SENDFILE check_conftest configure.d/copy_file_range.c && cpp_define HAS_COPY_FILE_RANGE if ! check_conftest configure.d/reallocarray.c; then - echo 'Disabling cmd/tr cmd/cut cmd/join' - target_filter="${target_filter} -e cmd/tr. -e cmd/cut. -e cmd/join." + echo 'Disabling cmd/df cmd/tr cmd/cut cmd/join' + target_filter="${target_filter} -e cmd/df. -e cmd/tr. -e cmd/cut. -e cmd/join." fi check_conftest configure.d/getopt_long.c && cpp_define HAS_GETOPT_LONG