diff options
| author | Rob Landley <rob@landley.net> | 2021-02-08 03:24:47 -0600 | 
|---|---|---|
| committer | Rob Landley <rob@landley.net> | 2021-02-08 03:24:47 -0600 | 
| commit | 8828d9cf77ec57604925753eeac45d0463a5b74f (patch) | |
| tree | a7b02fb84729feb07763f140de9efd85d4f0f92d | |
| parent | a079039934311f64a48e1010a97492a22126042e (diff) | |
| download | toybox-8828d9cf77ec57604925753eeac45d0463a5b74f.tar.gz | |
Yi-Yo Chiang reported that readlink() failures could corrupt archive
by not writing as much payload as the header promised.
| -rwxr-xr-x | tests/cpio.test | 2 | ||||
| -rw-r--r-- | toys/posix/cpio.c | 18 | 
2 files changed, 10 insertions, 10 deletions
diff --git a/tests/cpio.test b/tests/cpio.test index 11b3a5bf..6ab3665a 100755 --- a/tests/cpio.test +++ b/tests/cpio.test @@ -39,7 +39,7 @@ rm a bb ccc dddd  # archive dangling symlinks and empty files even if we cannot open them  touch a; chmod a-rwx a; ln -s a/cant b -toyonly testing "archives unreadable empty files" "cpio -o -H newc|cpio -it" "a\nb\n" "" "a\nb\n" +toyonly testing "archives unreadable empty files" "cpio -o -H newc|cpio -it" "b\na\n" "" "b\na\n"  chmod u+rw a; rm -f a b diff --git a/toys/posix/cpio.c b/toys/posix/cpio.c index 09c99ae1..31c777c9 100644 --- a/toys/posix/cpio.c +++ b/toys/posix/cpio.c @@ -229,6 +229,7 @@ void cpio_main(void)        struct stat st;        unsigned nlen, error = 0, zero = 0;        int len, fd = -1; +      char *link = 0;        ssize_t llen;        len = getline(&name, &size, stdin); @@ -236,11 +237,14 @@ void cpio_main(void)        if (name[len-1] == '\n') name[--len] = 0;        nlen = len+1;        if (lstat(name, &st) || (S_ISREG(st.st_mode) -          && st.st_size && (fd = open(name, O_RDONLY))<0)) +          && st.st_size && (fd = open(name, O_RDONLY))<0) +          || (S_ISLNK(st.st_mode) && !(link = xreadlink(name))))        {          perror_msg_raw(name);          continue;        } +      // encrypted filesystems can stat the wrong link size +      if (link) st.st_size = strlen(link);        if (FLAG(no_preserve_owner)) st.st_uid = st.st_gid = 0;        if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) st.st_size = 0; @@ -260,14 +264,9 @@ void cpio_main(void)          if (llen) xwrite(afd, &zero, 4-llen);          // Write out body for symlink or regular file -        llen = st.st_size; -        if (S_ISLNK(st.st_mode)) { -          if (readlink(name, toybuf, sizeof(toybuf)-1) == llen) -            xwrite(afd, toybuf, llen); -          else perror_msg("readlink '%s'", name); -        } else while (llen) { +        if (link) xwrite(afd, link, st.st_size); +        else for (llen = st.st_size; llen; llen -= nlen) {            nlen = llen > sizeof(toybuf) ? sizeof(toybuf) : llen; -          llen -= nlen;            // If read fails, write anyway (already wrote size in header)            if (nlen != readall(fd, toybuf, nlen))              if (!error++) perror_msg("bad read from file '%s'", name); @@ -276,7 +275,8 @@ void cpio_main(void)          llen = st.st_size & 3;          if (llen) xwrite(afd, &zero, 4-llen);        } -      close(fd); +      free(link); +      xclose(fd);      }      free(name);  | 
