avoid an infinite loop while decompressing invalid gzip files.

some minor CSE.  compare stat return value consistently.

thanks to tron for testing the first change.
This commit is contained in:
mrg 2005-08-28 10:17:50 +00:00
parent 2f6bd96c17
commit cde2923d5b

View File

@ -1,4 +1,4 @@
/* $NetBSD: gzip.c,v 1.72 2005/06/02 01:51:58 lukem Exp $ */ /* $NetBSD: gzip.c,v 1.73 2005/08/28 10:17:50 mrg Exp $ */
/* /*
* Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green * Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green
@ -32,7 +32,7 @@
#ifndef lint #ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green\n\ __COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green\n\
All rights reserved.\n"); All rights reserved.\n");
__RCSID("$NetBSD: gzip.c,v 1.72 2005/06/02 01:51:58 lukem Exp $"); __RCSID("$NetBSD: gzip.c,v 1.73 2005/08/28 10:17:50 mrg Exp $");
#endif /* not lint */ #endif /* not lint */
/* /*
@ -637,6 +637,8 @@ gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime
(int)(in_tot >> 24) & 0xff); (int)(in_tot >> 24) & 0xff);
if (i != 8) if (i != 8)
maybe_err("snprintf"); maybe_err("snprintf");
if (in_tot > 0xffffffff)
maybe_warn("input file size >= 4GB cannot be saved");
if (write(out, outbufp, i) != i) { if (write(out, outbufp, i) != i) {
maybe_warn("write"); maybe_warn("write");
in_tot = -1; in_tot = -1;
@ -730,8 +732,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
print_test(filename, 0); print_test(filename, 0);
#endif #endif
maybe_warn("failed to read stdin"); maybe_warn("failed to read stdin");
out_tot = -1; goto stop_and_fail;
goto stop;
} else if (in_size == 0) { } else if (in_size == 0) {
done_reading = 1; done_reading = 1;
} }
@ -751,8 +752,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
case GZSTATE_MAGIC0: case GZSTATE_MAGIC0:
if (*z.next_in != GZIP_MAGIC0) { if (*z.next_in != GZIP_MAGIC0) {
maybe_warnx("input not gziped (MAGIC0)"); maybe_warnx("input not gziped (MAGIC0)");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
ADVANCE(); ADVANCE();
state++; state++;
@ -764,8 +764,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
if (*z.next_in != GZIP_MAGIC1 && if (*z.next_in != GZIP_MAGIC1 &&
*z.next_in != GZIP_OMAGIC1) { *z.next_in != GZIP_OMAGIC1) {
maybe_warnx("input not gziped (MAGIC1)"); maybe_warnx("input not gziped (MAGIC1)");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
ADVANCE(); ADVANCE();
state++; state++;
@ -774,8 +773,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
case GZSTATE_METHOD: case GZSTATE_METHOD:
if (*z.next_in != Z_DEFLATED) { if (*z.next_in != Z_DEFLATED) {
maybe_warnx("unknown compression method"); maybe_warnx("unknown compression method");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
ADVANCE(); ADVANCE();
state++; state++;
@ -859,18 +857,37 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
case GZSTATE_INIT: case GZSTATE_INIT:
if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
maybe_warnx("failed to inflateInit"); maybe_warnx("failed to inflateInit");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
state++; state++;
break; break;
case GZSTATE_READ: case GZSTATE_READ:
error = inflate(&z, Z_FINISH); error = inflate(&z, Z_FINISH);
switch (error) {
/* Z_BUF_ERROR goes with Z_FINISH... */ /* Z_BUF_ERROR goes with Z_FINISH... */
if (error != Z_STREAM_END && error != Z_BUF_ERROR) case Z_BUF_ERROR:
/* Just need more input */ case Z_STREAM_END:
case Z_OK:
break; break;
case Z_NEED_DICT:
maybe_warnx("Z_NEED_DICT error");
goto stop_and_fail;
case Z_DATA_ERROR:
maybe_warnx("data stream error");
goto stop_and_fail;
case Z_STREAM_ERROR:
maybe_warnx("internal stream error");
goto stop_and_fail;
case Z_MEM_ERROR:
maybe_warnx("memory allocation error");
goto stop_and_fail;
default:
maybe_warn("unknown error from inflate(): %d",
error);
}
wr = BUFLEN - z.avail_out; wr = BUFLEN - z.avail_out;
if (wr != 0) { if (wr != 0) {
@ -882,8 +899,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
#endif #endif
write(out, outbufp, wr) != wr) { write(out, outbufp, wr) != wr) {
maybe_warn("error writing to output"); maybe_warn("error writing to output");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
out_tot += wr; out_tot += wr;
@ -909,8 +925,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
continue; continue;
} }
maybe_warnx("truncated input"); maybe_warnx("truncated input");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
origcrc = ((unsigned)z.next_in[0] & 0xff) | origcrc = ((unsigned)z.next_in[0] & 0xff) |
((unsigned)z.next_in[1] & 0xff) << 8 | ((unsigned)z.next_in[1] & 0xff) << 8 |
@ -919,8 +934,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
if (origcrc != crc) { if (origcrc != crc) {
maybe_warnx("invalid compressed" maybe_warnx("invalid compressed"
" data--crc error"); " data--crc error");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
} }
@ -942,8 +956,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
continue; continue;
} }
maybe_warnx("truncated input"); maybe_warnx("truncated input");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
origlen = ((unsigned)z.next_in[0] & 0xff) | origlen = ((unsigned)z.next_in[0] & 0xff) |
((unsigned)z.next_in[1] & 0xff) << 8 | ((unsigned)z.next_in[1] & 0xff) << 8 |
@ -953,8 +966,7 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
if (origlen != out_sub_tot) { if (origlen != out_sub_tot) {
maybe_warnx("invalid compressed" maybe_warnx("invalid compressed"
" data--length error"); " data--length error");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
} }
@ -963,13 +975,14 @@ gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
if (error < 0) { if (error < 0) {
maybe_warnx("decompression error"); maybe_warnx("decompression error");
out_tot = -1; goto stop_and_fail;
goto stop;
} }
state = GZSTATE_MAGIC0; state = GZSTATE_MAGIC0;
break; break;
} }
continue; continue;
stop_and_fail:
out_tot = 1;
stop: stop:
break; break;
} }
@ -1206,7 +1219,7 @@ file_compress(char *file, char *outfile, size_t outsize)
maybe_warn("couldn't close ouput"); maybe_warn("couldn't close ouput");
#ifndef SMALL #ifndef SMALL
if (stat(outfile, &osb) < 0) { if (stat(outfile, &osb) != 0) {
maybe_warn("couldn't stat: %s", outfile); maybe_warn("couldn't stat: %s", outfile);
goto bad_outfile; goto bad_outfile;
} }
@ -1445,13 +1458,13 @@ file_uncompress(char *file, char *outfile, size_t outsize)
/* /*
* if we can't stat the file don't remove the file. * if we can't stat the file don't remove the file.
*/ */
if (stat(outfile, &osb) < 0) { if (stat(outfile, &osb) != 0) {
maybe_warn("couldn't stat (leaving original): %s", maybe_warn("couldn't stat (leaving original): %s",
outfile); outfile);
return -1; return -1;
} }
if (osb.st_size != size) { if (osb.st_size != size) {
maybe_warn("stat gave different size: %" PRIdOFF maybe_warnx("stat gave different size: %" PRIdOFF
" != %" PRIdOFF " (leaving original)", " != %" PRIdOFF " (leaving original)",
size, osb.st_size); size, osb.st_size);
unlink(outfile); unlink(outfile);
@ -1650,7 +1663,7 @@ handle_pathname(char *path)
} }
retry: retry:
if (stat(path, &sb) < 0) { if (stat(path, &sb) != 0) {
/* lets try <path>.gz if we're decompressing */ /* lets try <path>.gz if we're decompressing */
if (dflag && s == NULL && errno == ENOENT) { if (dflag && s == NULL && errno == ENOENT) {
len = strlen(path); len = strlen(path);