From af46a3e21dd5d74710b67125a9848b5ba2e03e92 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 6 Feb 2022 12:39:32 -0800 Subject: [PATCH 3/4] Fix integer overflows in timestamp output * src/copyin.c (long_format): Fix some unlikely integer overflow bugs. Work even if (current_time - when) overflows, which is possible if time_t is unsigned. Do not assume that system integer types fit into unsigned long. Simplify by using %ju. No need for local tbuf array. --- src/copyin.c | 56 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/copyin.c b/src/copyin.c index fb30cf6..0af23a0 100644 --- a/src/copyin.c +++ b/src/copyin.c @@ -730,42 +730,50 @@ void long_format (struct cpio_file_stat *file_hdr, char const *link_name) { char mbuf[11]; - char tbuf[40]; - time_t when; - mode_string (file_hdr->c_mode, mbuf); mbuf[10] = '\0'; - /* Get time values ready to print. */ - when = file_hdr->c_mtime; - strcpy (tbuf, ctime (&when)); - if (current_time - when > 6L * 30L * 24L * 60L * 60L - || current_time - when < 0L) - { - /* The file is older than 6 months, or in the future. - Show the year instead of the time of day. */ - strcpy (tbuf + 11, tbuf + 19); - } - tbuf[16] = '\0'; - - printf ("%s %3lu ", mbuf, (unsigned long) file_hdr->c_nlink); + uintmax_t nlink = file_hdr->c_nlink; + printf ("%s %3ju ", mbuf, nlink); if (numeric_uid) - printf ("%-8u %-8u ", (unsigned int) file_hdr->c_uid, - (unsigned int) file_hdr->c_gid); + { + uintmax_t uid = file_hdr->c_uid, gid = file_hdr->c_gid; + printf ("%-8ju %-8ju ", uid, gid); + } else printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid), getgroup (file_hdr->c_gid)); if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK) - printf ("%3lu, %3lu ", - (unsigned long) file_hdr->c_rdev_maj, - (unsigned long) file_hdr->c_rdev_min); + { + uintmax_t maj = file_hdr->c_rdev_maj, min = file_hdr->c_rdev_min; + printf ("%3ju, %3ju ", maj, min); + } else - printf ("%8"PRIuMAX" ", (uintmax_t) file_hdr->c_filesize); + { + uintmax_t filesize = file_hdr->c_filesize; + printf ("%8ju ", filesize); + } - printf ("%s ", tbuf + 4); + /* Get time values ready to print. Do not worry about ctime failing, + or a year outside the range 1000-9999, since 0 <= WHEN < 2**33. */ + time_t when = file_hdr->c_mtime; + char *tbuf = ctime (&when); + int six_months = 6 * 30 * 24 * 60 * 60; + bool recent = ((current_time < six_months + || current_time - six_months <= when) + && when <= current_time); + if (!recent) + { + /* The file is older than 6 months, or in the future. + Show the year instead of the time of day. */ + memcpy (tbuf + 11, tbuf + 19, sizeof " 1970" - 1); + } + tbuf[16] = ' '; + tbuf[17] = '\0'; + printf ("%s", tbuf + 4); printf ("%s", quotearg (file_hdr->c_name)); if (link_name) @@ -773,7 +781,7 @@ long_format (struct cpio_file_stat *file_hdr, char const *link_name) printf (" -> "); printf ("%s", quotearg (link_name)); } - putc ('\n', stdout); + putchar ('\n'); } /* Read a pattern file (for the -E option). Put a list of -- 2.32.0