Fix some problems with negative and out-of-range integers.

Original problem reported for HP-UX LVM v2.2 by Michael White in
<http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00000.html>.
This patch fixes some other gotchas that I noticed.
* gnulib.modules: Add extern-inline.
* src/common.h: Use _GL_INLINE_HEADER_BEGIN, _GL_INLINE_HEADER_END.
(COMMON_INLINE, max, min): New macros.
(represent_uintmax, valid_timespec): New inline functions.
(SYSINT_BUFSIZE): New constant.
(sysinttostr, strtosysint, decode_timespec): New decls.
* src/create.c (start_private_header): Silently bring the time_t
value into range; it is now the caller's responsibility to deal
with any overflow error.  Use uid 0 and gid 0 rather than the
user's uid/gid, since the faked header isn't "owned" by the user
and the uid/gid could in theory be out of range.  Leave major and
minor zeroed.
(FILL): Remove.
(write_gnu_long_link): Let start_private_header zero things out.
* src/create.c (write_gnu_long_link, write_extended):
* src/xheader.c (xheader_write_global):
Use start_time, not current time; no point hammering on the clock.
* src/compare.c (diff_multivol): Check that offset, size are in range.
* src/incremen.c (read_incr_db_01, write_directory_file_entry):
Allow negative time_t, dev_t, and ino_t.
* src/list.c (max): Remove (moved to common.h).
(read_header): Check that size is in range.
(from_header): Return intmax_t, not uintmax_t, to allow negative.
All callers changed.  At compile time, check assumptions about
intmax_t and uintmax_t.  Use bool for booleans.  Avoid overflow
hassles on picky hosts.
(mode_from_header): Last arg is now bool *, not unsigned *.
All callers changed.
(simple_print_header): Do not assume UID, GID fit in 'long'.
* src/list.c (from_header):
* src/xheader.c (out_of_range_header):
Arg is now a plain minimum value, not minus minval converted to
uintmax_t.  All callers changed.
* src/misc.c (COMMON_INLINE): New macro.
(sysinttostr, strtosysint, decode_timespec): New functions.
* src/sparse.c (oldgnu_add_sparse, oldgnu_fixup_header)
(star_fixup_header):
Check for offset overflow.
(decode_num): Clear errno before calling strtoumax.
* src/tar.c (expand_pax_option): Don't discard nanoseconds.
* src/xheader.c (assign_time_option): Allow negative time_t.
(decode_record): Simplify, since out-of-range string is guaranteed
to produce a value exceeding len_max.
(xheader_read): Last arg is off_t, not size_t.
Caller should diagnose negative arg, as needed.
Check that it's in range.
(enum decode_time_status): Remove.
(_decode_time): Remove, folding into decode_time.
(decode_time): Return bool, not enum decode_time_status.
Rely on decode_timespec to do most of the work.
(code_signed_num): New function.
(code_num): Use it.
(decode_signed_num): New function.
(decode_num): Use it.
(gid_coder, gid_decoder, uid_coder, uid_decoder, sparse_map_decoder)
(sparse_map_decoder): Code and decode negative values.
(sparse_map_decoder): Improve check for out-of-range values.
* tests/time01.at: New file.
* tests/Makefile.am (TESTSUITE_AT): Add it.
* tests/testsuite.at: Include it.
This commit is contained in:
Paul Eggert
2012-12-22 20:41:23 -08:00
parent d8ac237663
commit df7b55a8f6
13 changed files with 472 additions and 315 deletions

View File

@@ -157,6 +157,7 @@ TESTSUITE_AT = \
spmvp00.at\
spmvp01.at\
spmvp10.at\
time01.at\
truncate.at\
update.at\
update01.at\

View File

@@ -284,6 +284,8 @@ m4_include([lustar01.at])
m4_include([lustar02.at])
m4_include([lustar03.at])
m4_include([time01.at])
m4_include([multiv01.at])
m4_include([multiv02.at])
m4_include([multiv03.at])
@@ -357,4 +359,3 @@ m4_include([star/ustar-big-2g.at])
m4_include([star/ustar-big-8g.at])
m4_include([star/pax-big-10g.at])

70
tests/time01.at Normal file
View File

@@ -0,0 +1,70 @@
# Test time stamps for GNU tar. -*- Autotest -*-
#
# Copyright 2012 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# written by Paul Eggert
AT_SETUP([time: tricky time stamps])
AT_KEYWORDS([time time01])
AT_TAR_CHECK([
export TZ=UTC0
mkdir dir
# Test files with time stamps that are near common sources of error,
# typically near powers of 2 (for seconds) or near 0, 1970, or 9999 (years).
# Use GNU-style @ notation for very large time stamps, since they
# typically don't render into years correctly due to int overflow.
for s in \
@-9223372036854775809 @-9223372036854775808 @-9223372036854775807 \
0000-01-01T00:00:00 0000-01-01T00:00:01 \
0000-01-02T00:00:00 \
1697-10-17T11:03:27 1697-10-17T11:03:28 1697-10-17T11:03:29 \
1833-11-24T17:31:43 1833-11-24T17:31:44 1833-11-24T17:31:45 \
1901-12-13T20:45:51 1901-12-13T20:45:52 1901-12-13T20:45:53 \
1901-12-14T20:45:51 \
1969-12-31T23:59:58 1969-12-31T23:59:59 \
1970-01-01T00:00:00 1970-01-01T00:00:01 \
2038-01-18T03:14:07 \
2038-01-19T03:14:07 2038-01-19T03:14:08 \
2106-02-07T06:28:15 2106-02-07T06:28:16 \
2242-03-16T12:56:31 2242-03-16T12:56:32 \
9999-12-31T23:59:58 9999-12-31T23:59:59 \
@9223372036854775807 @9223372036854775808
do
# Skip a time stamp $s if it's out of range for this platform,
# of if it uses a notation that this platform does not recognize.
touch -d $s dir/f$s >/dev/null 2>&1 || continue
# Likewise for $s.1. If $s is the most negative time stamp and
# time stamps are signed, then $s.1 is out of range.
touch -d $s.1 dir/f$s.$ns >/dev/null 2>&1 || continue
for frac in 01 001 00001 000001 0000001 00000001 000000001 0000000001 \
9 99 999 99999 999999 9999999 99999999 999999999 9999999999
do
touch -d $s.$frac dir/f$s.$frac
done
done
tar -c -f archive.tar dir
tar -d -f archive.tar dir
],
[0],
[], [], [], [],
[pax])
AT_CLEANUP