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:
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