On Sun, 14 Feb 2016, Philip Guenther wrote:
> On Sun, 14 Feb 2016, Nicolas Bedos wrote:
...
> > >Fix:
> > I did some digging and it seems pax gets stuck in a loop after
> > calling node_creat (file_subs.c) to create /tmp/foo/bar:
> ...
> > The first argument of chk_path seems to end with '/' because of the
> > cpio format. I could not reproduce the problem with the ustar
> > format. I did not look any further since I think it is chk_path
> > which is at fault here.
>
> It doesn't occur when reading ustar format input because a filename with a
> trailing slash is already specially handled there to provide compat with
> the old tar format where directories are stored with a trailing slash.
...and since pax's tar format code only trims a single trailing slash, it
will loop even in that case if you add more than one trailing slash.
Indeed, if you add more than one trailing slash in general then it'll
still hang despite your patch: to fix it the code needs to be able to
detect when its reached an arbitrary number of trailing slashes.
So, I think a diff like this is in order. This also lets it skip extra
slashes in the middle of the path and avoid the checks that would be
duplicated.
Look good to everyone?
Philip Guenther
--- file_subs.c 19 Mar 2015 05:14:24 -0000 1.47
+++ file_subs.c 15 Feb 2016 09:35:57 -0000
@@ -597,6 +597,7 @@ int
chk_path(char *name, uid_t st_uid, gid_t st_gid)
{
char *spt = name;
+ char *next;
struct stat sb;
int retval = -1;
@@ -613,6 +614,17 @@ chk_path(char *name, uid_t st_uid, gid_t
spt = strchr(spt, '/');
if (spt == NULL)
break;
+
+ /*
+ * skip over duplicate slashes; stop if there're only
+ * trailing slashes left
+ */
+ next = spt + 1;
+ while (*next == '/')
+ next++;
+ if (*next == '\0')
+ break;
+
*spt = '\0';
/*
@@ -625,7 +637,8 @@ chk_path(char *name, uid_t st_uid, gid_t
* required (do an access()).
*/
if (lstat(name, &sb) == 0) {
- *(spt++) = '/';
+ *spt = '/';
+ spt = next;
continue;
}
@@ -659,7 +672,8 @@ chk_path(char *name, uid_t st_uid, gid_t
set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));
add_dir(name, &sb, 1);
}
- *(spt++) = '/';
+ *spt = '/';
+ spt = next;
continue;
}
return(retval);