diff options
author | George Koehler <gkoehler@cvs.openbsd.org> | 2022-06-18 03:23:20 +0000 |
---|---|---|
committer | George Koehler <gkoehler@cvs.openbsd.org> | 2022-06-18 03:23:20 +0000 |
commit | 05aab66b1469951129df969407d2d23809df8dd5 (patch) | |
tree | d0dc59d37ff07de3438e37320d9b6f4da6a0f5d3 /usr.bin/compress | |
parent | 64c0ca569b8e45312dcfb0eac26658b6505a95d2 (diff) |
Fix gzip byte counts with 32-bit integers
If zlib is without our local change in lib/libz/zlib.h r1.7, then
s->z_stream.total_in and s->z_stream.total_out might overflow on
architectures where uLong has 32 bits. After overflow, the total
would be 4G below the correct total.
Calculate our own 64-bit totals. When decompressing, take
(uLong)s->z_stream.total_in as a total modulo ULONG_MAX + 1.
ok tb@
Diffstat (limited to 'usr.bin/compress')
-rw-r--r-- | usr.bin/compress/gzopen.c | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/usr.bin/compress/gzopen.c b/usr.bin/compress/gzopen.c index 7fd848cf72e..eebc943543e 100644 --- a/usr.bin/compress/gzopen.c +++ b/usr.bin/compress/gzopen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gzopen.c,v 1.34 2016/09/03 12:29:30 tedu Exp $ */ +/* $OpenBSD: gzopen.c,v 1.35 2022/06/18 03:23:19 gkoehler Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff @@ -260,9 +260,13 @@ int gz_read(void *cookie, char *buf, int len) { gz_stream *s = (gz_stream*)cookie; + uLong old_total_in; u_char *start = buf; /* starting point for crc computation */ int error = Z_OK; + /* z_stream.total_in might overflow uLong. */ + old_total_in = s->z_stream.total_in; + s->z_stream.next_out = buf; s->z_stream.avail_out = len; @@ -304,29 +308,28 @@ gz_read(void *cookie, char *buf, int len) } s->z_hlen += 2 * sizeof(int32_t); - /* Add byte counts from the finished stream. */ - s->z_total_in += s->z_stream.total_in; - s->z_total_out += s->z_stream.total_out; - /* Check for the existence of an appended file. */ if (get_header(s, NULL, 0) != 0) { s->z_eof = 1; break; } + s->z_total_in += (uLong)(s->z_stream.total_in - + old_total_in); inflateReset(&(s->z_stream)); s->z_crc = crc32(0L, Z_NULL, 0); + old_total_in = 0; error = Z_OK; } } s->z_crc = crc32(s->z_crc, start, (uInt)(s->z_stream.next_out - start)); len -= s->z_stream.avail_out; - + s->z_total_in += (uLong)(s->z_stream.total_in - old_total_in); + s->z_total_out += len; return (len); bad: - /* Add byte counts from the finished stream. */ - s->z_total_in += s->z_stream.total_in; - s->z_total_out += s->z_stream.total_out; + s->z_total_in += (uLong)(s->z_stream.total_in - old_total_in); + s->z_total_out += (len - s->z_stream.avail_out); return (-1); } @@ -431,6 +434,8 @@ gz_write(void *cookie, const char *buf, int len) while (s->z_stream.avail_in != 0) { if (s->z_stream.avail_out == 0) { + s->z_total_out += Z_BUFSIZE; + if (write(s->z_fd, s->z_buf, Z_BUFSIZE) != Z_BUFSIZE) break; s->z_stream.next_out = s->z_buf; @@ -441,7 +446,9 @@ gz_write(void *cookie, const char *buf, int len) } s->z_crc = crc32(s->z_crc, buf, len); - return (int)(len - s->z_stream.avail_in); + len -= s->z_stream.avail_in; + s->z_total_in += len; + return len; } int @@ -463,6 +470,8 @@ gz_flush(void *cookie, int flush) len = Z_BUFSIZE - s->z_stream.avail_out; if (len != 0) { + s->z_total_out += len; + if (write(s->z_fd, s->z_buf, len) != len) return Z_ERRNO; s->z_stream.next_out = s->z_buf; @@ -516,14 +525,8 @@ gz_close(void *cookie, struct z_info *info, const char *name, struct stat *sb) info->mtime = s->z_time; info->crc = s->z_crc; info->hlen = s->z_hlen; - if (s->z_mode == 'r') { - info->total_in = s->z_total_in; - info->total_out = s->z_total_out; - } else { - info->total_in = s->z_stream.total_in; - info->total_out = s->z_stream.total_out; - } - + info->total_in = s->z_total_in; + info->total_out = s->z_total_out; } setfile(name, s->z_fd, sb); |