Control: tag -1 + patch
On Tue, Oct 12, 2021 at 05:40:42PM +1000, Alexander Zangerl wrote:
> sorry, but i disagree. yes, it is a bug. but no, it is not severity
> important: a 2000+ levels deep directory hierarchy has no
> practical relevance whatsoever.
> and a workaround exists: don't create ridiculously deep hierarchies ;-)
I mean, yeah, fair enough; I have this explicitly for testing coreutils.
Below you'll find a patch for 0.4b47-2, replacing the static MAXPATHLEN
path buffer in treescan() with a dynamically allocated one. This fixes
both the original bug (down to directory depths I assume no-one
has achieved before), and the
./[very long path redacted]: name exceeds 4096 char
diagnostic I got when I originally bumped ulimit -s.
It does use asprintf(3) ‒ while an extension,
it's universal across the extant Berkeley and Solaris derivatives.
-x mode still panics since the paths *are* longer than PATH_MAX, but you
can't pass those to syscalls anyway and restructuring around that would
be non-trivial (in this case, your workaround should be applied
instead :P).
Best,
наб
Date: Wed, 29 Dec 2021 16:26:07 +0100
From: наб
Subject: Don't trust MAXPATHLEN in treescan()
Dynamically allocate the path buffer:
this both allows paths longer than PATH_MAX,
and thins the stack frame considerably
(no longer segfaulting on a Very Deep tree
on Debian-default 8k ulimit -s)
--- dump-0.4b47.orig/restore/dirs.c
+++ dump-0.4b47/restore/dirs.c
@@ -287,9 +287,8 @@ treescan(char *pname, dump_ino_t ino, lo
{
struct inotab *itp;
struct direct *dp;
- int namelen;
off_t bpt;
- char locname[MAXPATHLEN + 1];
+ char *locname;
itp = inotablookup(ino);
if (itp == NULL) {
@@ -308,9 +307,6 @@ treescan(char *pname, dump_ino_t ino, lo
* begin search through the directory
* skipping over "." and ".."
*/
- namelen = snprintf(locname, sizeof(locname), "%s/", pname);
- if (namelen >= (int)sizeof(locname))
- namelen = sizeof(locname) - 1;
rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
dp = rst_readdir(dirp); /* "." */
if (dp != NULL && strcmp(dp->d_name, ".") == 0)
@@ -328,15 +324,13 @@ treescan(char *pname, dump_ino_t ino, lo
* a zero inode signals end of directory
*/
while (dp != NULL) {
- locname[namelen] = '\0';
- if (namelen + dp->d_namlen >= (int)sizeof(locname)) {
- fprintf(stderr, "%s%s: name exceeds %ld char\n",
- locname, dp->d_name, (long)sizeof(locname) - 1);
- } else {
- (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
- treescan(locname, dp->d_ino, todo);
- rst_seekdir(dirp, bpt, itp->t_seekpt);
+ if (asprintf(, "%s/%.*s", pname, (int)dp->d_namlen,
dp->d_name) == -1) {
+ panic("Error: %s\n", strerror(errno));
+ abort();
}
+ treescan(locname, dp->d_ino, todo);
+ free(locname);
+ rst_seekdir(dirp, bpt, itp->t_seekpt);
dp = rst_readdir(dirp);
bpt = rst_telldir(dirp);
}
signature.asc
Description: PGP signature