aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2021-02-08 03:24:47 -0600
committerRob Landley <rob@landley.net>2021-02-08 03:24:47 -0600
commit8828d9cf77ec57604925753eeac45d0463a5b74f (patch)
treea7b02fb84729feb07763f140de9efd85d4f0f92d
parenta079039934311f64a48e1010a97492a22126042e (diff)
downloadtoybox-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-xtests/cpio.test2
-rw-r--r--toys/posix/cpio.c18
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);