CVE-2016-9841 (C, published 2017-05-23T04:29Z)
Description: value: inffast.c in zlib 1.2.8 might allow context-dependent attackers to have unspecified impact by leveraging improper pointer arithmetic.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/madler/zlib
Files changed:
inffast.c
Commit message: Use post-increment only in inffast.c.

An old inffast.c optimization turns out to not be optimal anymore
with modern compilers, and furthermore was not compliant with the
C standard, for which decrementing a pointer before its allocated
memory is undefined. Per the recommendation of a security audit of
the zlib code by Trail of Bits and TrustInSoft, in support of the
Mozilla Foundation, this "optimization" was removed, in order to
avoid the possibility of undefined behavior.


Vulnerable code:
/* Allow machine dependent optimization for post-increment or pre-increment.
   Based on testing to date,
   Pre-increment preferred for:
   - PowerPC G3 (Adler)
   - MIPS R5000 (Randers-Pehrson)
   Post-increment preferred for:
   - none
   No measurable difference:
   - Pentium III (Anderson)
   - M68060 (Nikl)
 */
#ifdef POSTINC
#  define OFF 0
#  define PUP(a) *(a)++
#else
#  define OFF 1
#  define PUP(a) *++(a)
#endif

    in = strm->next_in - OFF;
    out = strm->next_out - OFF;
            hold += (unsigned long)(PUP(in)) << bits;
            hold += (unsigned long)(PUP(in)) << bits;
            PUP(out) = (unsigned char)(here.val);
                    hold += (unsigned long)(PUP(in)) << bits;
                hold += (unsigned long)(PUP(in)) << bits;
                hold += (unsigned long)(PUP(in)) << bits;
                    hold += (unsigned long)(PUP(in)) << bits;
                        hold += (unsigned long)(PUP(in)) << bits;
                                PUP(out) = 0;
                            PUP(out) = 0;
                                PUP(out) = PUP(from);
                    from = window - OFF;
                                PUP(out) = PUP(from);
                                PUP(out) = PUP(from);
                            from = window - OFF;
                                    PUP(out) = PUP(from);
                                PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                            PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                            PUP(out) = PUP(from);
    strm->next_in = in + OFF;
    strm->next_out = out + OFF;

Fixed code:
    in = strm->next_in;
    out = strm->next_out;
            hold += (unsigned long)(*in++) << bits;
            hold += (unsigned long)(*in++) << bits;
            *out++ = (unsigned char)(here.val);
                    hold += (unsigned long)(*in++) << bits;
                hold += (unsigned long)(*in++) << bits;
                hold += (unsigned long)(*in++) << bits;
                    hold += (unsigned long)(*in++) << bits;
                        hold += (unsigned long)(*in++) << bits;
                                *out++ = 0;
                            *out++ = 0;
                                *out++ = *from++;
                    from = window;
                                *out++ = *from++;
                                *out++ = *from++;
                            from = window;
                                    *out++ = *from++;
                                *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                            *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                            *out++ = *from++;
    strm->next_in = in;
    strm->next_out = out;