Summary
gz_reset() initializes state->past only inside the state->mode == GZ_READ
branch, but since commit
a4e4521
gzseek64() and gztell64() read it in either mode. gz_open() allocates
gz_state with a plain malloc() and does not zero it, so a write-mode handle reads
past out of indeterminate heap.
Two consequences, both write-mode only:
- Silent output corruption. Two
SEEK_CUR seeks with no write between them can
drop the accumulated zero-fill, producing a well-formed gzip stream with a valid
CRC and the wrong contents.
gztell() returns the wrong position after a deferred seek, breaking the
documented gztell(file) == gzseek(file, 0L, SEEK_CUR) equivalence in zlib.h.
Affected: v1.3.1.2, v1.3.2, master, develop — all reproduced below.
v1.3.1 and earlier are unaffected. Still present on develop.
Root cause
gzlib.c, gz_reset():
local void gz_reset(gz_statep state) {
state->x.have = 0; /* no output data available */
if (state->mode == GZ_READ) { /* for reading ... */
state->eof = 0; /* not at end of file */
state->past = 0; /* <-- only initialized for reading */
state->how = LOOK;
state->junk = -1;
}
else /* for writing ... */
state->reset = 0;
state->again = 0;
state->skip = 0; /* no seek request pending */
...
}
The two write-mode readers, both added by a4e4521:
/* gzseek64() */
else {
offset += state->past ? 0 : state->skip;
state->skip = 0;
}
/* gztell64() */
return state->x.pos + (state->past ? 0 : state->skip);
Summary
gz_reset()initializesstate->pastonly inside thestate->mode == GZ_READbranch, but since commit
a4e4521gzseek64()andgztell64()read it in either mode.gz_open()allocatesgz_statewith a plainmalloc()and does not zero it, so a write-mode handle readspastout of indeterminate heap.Two consequences, both write-mode only:
SEEK_CURseeks with no write between them candrop the accumulated zero-fill, producing a well-formed gzip stream with a valid
CRC and the wrong contents.
gztell()returns the wrong position after a deferred seek, breaking thedocumented
gztell(file) == gzseek(file, 0L, SEEK_CUR)equivalence inzlib.h.Affected:
v1.3.1.2,v1.3.2,master,develop— all reproduced below.v1.3.1and earlier are unaffected. Still present ondevelop.Root cause
gzlib.c,gz_reset():The two write-mode readers, both added by
a4e4521: