summarylogtreecommitdiffstats
path: root/add-overflow-checks.patch
blob: 6f1f7b28993ba3b65a2756e943e598d81a1a53db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
Description: Add arithmetic overflow checks in woff encoding routines
Origin: mozilla-central, https://hg.mozilla.org/mozilla-central/rev/69eb050f2c0a
Last-Update: 2013-04-11

--- a/woff.c
+++ b/woff.c
@@ -89,10 +89,15 @@
   const uint32_t * csumPtr;
   const uint32_t * csumEnd;
   uint32_t csum = 0;
-  uint32_t length = LONGALIGN(READ32BE(dirEntry->length));
+  uint32_t length = READ32BE(dirEntry->length);
   uint32_t offset = READ32BE(dirEntry->offset);
   uint32_t tag;
-  if ((offset & 3) != 0) {
+  if (LONGALIGN(length) < length) { /* overflow */
+    return csum;
+  } else {
+    length = LONGALIGN(length);
+  }
+  if ((offset & 3) != 0) { /* invalid - not properly aligned */
     return csum;
   }
   if (length > sfntLen || offset > sfntLen - length) {
@@ -224,6 +229,9 @@
       if (tag == TABLE_TAG_DSIG) {
         status |= eWOFF_warn_removed_DSIG;
         removedDsigSize = READ32BE(sfntDir[tableIndex].length);
+        if (LONGALIGN(removedDsigSize) < removedDsigSize) {
+          FAIL(eWOFF_invalid);
+        }
         continue;
       }
     }
@@ -235,6 +243,7 @@
   qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets);
 
   /* initially, allocate space for header and directory */
+  /* cannot be too big because numTables is 16-bit */
   tableOffset = sizeof(woffHeader) + numTables * sizeof(woffDirEntry);
   woffData = (uint8_t *) malloc(tableOffset);
   if (!woffData) {
@@ -277,7 +286,15 @@
     if (sourceLen > sfntLen || sourceOffset > sfntLen - sourceLen) {
       FAIL(eWOFF_invalid);
     }
-    destLen = LONGALIGN(compressBound(sourceLen));
+    destLen = compressBound(sourceLen);
+    if (LONGALIGN(destLen) < destLen) {
+      /* something weird is going on if this overflows! */
+      FAIL(eWOFF_invalid);
+    }
+    destLen = LONGALIGN(destLen);
+    if (tableOffset + destLen < tableOffset) {
+      FAIL(eWOFF_invalid);
+    }
     woffData = (uint8_t *) realloc(woffData, tableOffset + destLen);
     if (!woffData) {
       FAIL(eWOFF_out_of_memory);
@@ -291,13 +308,19 @@
     }
     if (destLen < sourceLen) {
       /* compressed table was smaller */
-      tableOffset += destLen;
+      tableOffset += destLen; /* checked for potential overflow above */
       WOFFDIR[newIndex].compLen = READ32BE(destLen);
     } else {
       /* compression didn't make it smaller, so store original data instead */
+      if (LONGALIGN(sourceLen) < sourceLen) {
+        FAIL(eWOFF_invalid); /* overflow, bail out */
+      }
       destLen = sourceLen;
       /* reallocate to ensure enough space for the table,
          plus potential padding after it */
+      if (tableOffset + LONGALIGN(sourceLen) < tableOffset) {
+        FAIL(eWOFF_invalid); /* overflow, bail out */
+      }
       woffData = (uint8_t *) realloc(woffData,
                                      tableOffset + LONGALIGN(sourceLen));
       if (!woffData) {
@@ -306,6 +329,9 @@
       /* copy the original data into place */
       memcpy(woffData + tableOffset,
              sfntData + READ32BE(sfntDir[oldIndex].offset), sourceLen);
+      if (tableOffset + sourceLen < tableOffset) {
+        FAIL(eWOFF_invalid); /* overflow, bail out */
+      }
       tableOffset += sourceLen;
       WOFFDIR[newIndex].compLen = WOFFDIR[newIndex].origLen;
     }
@@ -316,7 +342,13 @@
     }
 
     /* update total size of uncompressed OpenType with table size */
+    if (totalSfntSize + sourceLen < totalSfntSize) {
+      FAIL(eWOFF_invalid); /* overflow, bail out */
+    }
     totalSfntSize += sourceLen;
+    if (LONGALIGN(totalSfntSize) < totalSfntSize) {
+      FAIL(eWOFF_invalid);
+    }
     totalSfntSize = LONGALIGN(totalSfntSize);
   }
 
@@ -442,10 +474,20 @@
 
   totalSize = tableLimit; /* already long-aligned */
   if (metaCompLen) {
+    if (totalSize + metaCompLen < totalSize) {
+      FAIL(eWOFF_invalid);
+    }
     totalSize += metaCompLen;
   }
   if (privLen) {
-    totalSize = LONGALIGN(totalSize) + privLen;
+    if (LONGALIGN(totalSize) < totalSize) {
+      FAIL(eWOFF_invalid);
+    }
+    totalSize = LONGALIGN(totalSize);
+    if (totalSize + privLen < totalSize) {
+      FAIL(eWOFF_invalid);
+    }
+    totalSize += privLen;
   }
   newData = malloc(totalSize);
   if (!newData) {