Fix InflateBack corner case

This handles the case where a zlib user could rely on InflateBack
API to decompress content.

The NEON optimization assumes that it can perform wide stores, sometimes
overwriting data on the output pointer (but never overflowing the buffer
end as it has enough room for the write).

For infback there is no such guarantees (i.e. no extra wiggle room),
which can result in illegal operations. This patch fixes the potential
issue by falling back to the non-optimized code for such cases.

Also it adds some comments about the entry assumptions in inflate and
writes out a defined value at the write buffer to identify where
the real data has ended (helpful while debugging).

Bug: 769880
Change-Id: I08130e4d012e55fb1a114394b88df7e9d8a6542f
Reviewed-on: https://chromium-review.googlesource.com/749732
Reviewed-by: Chris Blume <cblume@chromium.org>
Commit-Queue: Adenilson Cavalcanti <cavalcantii@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#513830}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 0bb11040792edc5b28fcb710fc4c01fedd98c97c
diff --git a/BUILD.gn b/BUILD.gn
index f955f60..ea51103 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -131,15 +131,12 @@
 
   if (current_cpu == "arm" || current_cpu == "arm64") {
     if (arm_use_neon) {
-      # TODO: handle InflateBack case, see crbug.com/769880.
-      sources -= [
-        "inffast.c",
-        "inflate.c",
-      ]
+      sources -= [ "inflate.c" ]
       sources += [
         "contrib/optimizations/arm/chunkcopy_arm.h",
         "contrib/optimizations/chunkcopy.h",
         "contrib/optimizations/inffast_chunky.c",
+        "contrib/optimizations/inffast_chunky.h",
         "contrib/optimizations/inflate.c",
       ]
     }
diff --git a/contrib/optimizations/inffast_chunky.c b/contrib/optimizations/inffast_chunky.c
index 9170d33..e2bc735 100644
--- a/contrib/optimizations/inffast_chunky.c
+++ b/contrib/optimizations/inffast_chunky.c
@@ -6,7 +6,7 @@
 #include "zutil.h"
 #include "inftrees.h"
 #include "inflate.h"
-#include "inffast.h"
+#include "contrib/optimizations/inffast_chunky.h"
 #include "contrib/optimizations/chunkcopy.h"
 
 #ifdef ASMINF
@@ -28,6 +28,10 @@
         strm->avail_out >= 258
         start >= strm->avail_out
         state->bits < 8
+        strm->next_out[0..strm->avail_out] does not overlap with
+              strm->next_in[0..strm->avail_in]
+        strm->state->window is allocated with an additional
+              CHUNKCOPY_CHUNK_SIZE-1 bytes of padding beyond strm->state->wsize
 
    On return, state->mode is one of:
 
@@ -48,7 +52,7 @@
       requires strm->avail_out >= 258 for each loop to avoid checking for
       output space.
  */
-void ZLIB_INTERNAL inflate_fast(strm, start)
+void ZLIB_INTERNAL inflate_fast_chunky(strm, start)
 z_streamp strm;
 unsigned start;         /* inflate()'s starting value for strm->avail_out */
 {
diff --git a/contrib/optimizations/inffast_chunky.h b/contrib/optimizations/inffast_chunky.h
new file mode 100644
index 0000000..7f033f2
--- /dev/null
+++ b/contrib/optimizations/inffast_chunky.h
@@ -0,0 +1,12 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * Copyright (C) 2017 ARM, Inc.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast_chunky OF((z_streamp strm, unsigned start));
diff --git a/contrib/optimizations/inflate.c b/contrib/optimizations/inflate.c
index 0451d74..152f174 100644
--- a/contrib/optimizations/inflate.c
+++ b/contrib/optimizations/inflate.c
@@ -83,7 +83,7 @@
 #include "zutil.h"
 #include "inftrees.h"
 #include "inflate.h"
-#include "inffast.h"
+#include "contrib/optimizations/inffast_chunky.h"
 #include "contrib/optimizations/chunkcopy.h"
 
 #ifdef MAKEFIXED
@@ -1056,7 +1056,7 @@
         case LEN:
             if (have >= 6 && left >= 258) {
                 RESTORE();
-                inflate_fast(strm, out);
+                inflate_fast_chunky(strm, out);
                 LOAD();
                 if (state->mode == TYPE)
                     state->back = -1;
@@ -1262,6 +1262,16 @@
        Note: a memory error from inflate() is non-recoverable.
      */
   inf_leave:
+   /* We write a defined value in the unused space to help mark
+    * where the stream has ended. We don't use zeros as that can
+    * mislead clients relying on undefined behavior (i.e. assuming
+    * that the data is over when the buffer has a zero/null value).
+    */
+   if (left >= CHUNKCOPY_CHUNK_SIZE)
+      memset(put, 0x55, CHUNKCOPY_CHUNK_SIZE);
+   else
+      memset(put, 0x55, left);
+
     RESTORE();
     if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
             (state->mode < CHECK || flush != Z_FINISH)))