Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/Entries.h
Line
Count
Source (jump to first uncovered line)
1
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
// This header file defines the storage types of the actual safebrowsing
7
// chunk data, which may be either 32-bit hashes or complete 256-bit hashes.
8
// Chunk numbers are represented in ChunkSet.h.
9
10
#ifndef SBEntries_h__
11
#define SBEntries_h__
12
13
#include "nsTArray.h"
14
#include "nsString.h"
15
#include "nsICryptoHash.h"
16
#include "nsNetUtil.h"
17
#include "nsIOutputStream.h"
18
#include "nsClassHashtable.h"
19
#include "nsDataHashtable.h"
20
#include "plbase64.h"
21
22
namespace mozilla {
23
namespace safebrowsing {
24
25
0
#define PREFIX_SIZE   4
26
0
#define COMPLETE_SIZE 32
27
28
// This is the struct that contains 4-byte hash prefixes.
29
template <uint32_t S, class Comparator>
30
struct SafebrowsingHash
31
{
32
  static_assert(S >= 4, "The SafebrowsingHash should be at least 4 bytes.");
33
34
  static const uint32_t sHashSize = S;
35
  typedef SafebrowsingHash<S, Comparator> self_type;
36
  uint8_t buf[S];
37
38
0
  nsresult FromPlaintext(const nsACString& aPlainText) {
39
0
    // From the protocol doc:
40
0
    // Each entry in the chunk is composed
41
0
    // of the SHA 256 hash of a suffix/prefix expression.
42
0
    nsresult rv;
43
0
    nsCOMPtr<nsICryptoHash> hash =
44
0
      do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
45
0
    NS_ENSURE_SUCCESS(rv, rv);
46
0
47
0
    rv = hash->Init(nsICryptoHash::SHA256);
48
0
    NS_ENSURE_SUCCESS(rv, rv);
49
0
50
0
    rv = hash->Update
51
0
      (reinterpret_cast<const uint8_t*>(aPlainText.BeginReading()),
52
0
       aPlainText.Length());
53
0
    NS_ENSURE_SUCCESS(rv, rv);
54
0
55
0
    nsAutoCString hashed;
56
0
    rv = hash->Finish(false, hashed);
57
0
    NS_ENSURE_SUCCESS(rv, rv);
58
0
59
0
    NS_ASSERTION(hashed.Length() >= sHashSize,
60
0
                 "not enough characters in the hash");
61
0
62
0
    memcpy(buf, hashed.BeginReading(), sHashSize);
63
0
64
0
    return NS_OK;
65
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::FromPlaintext(nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::FromPlaintext(nsTSubstring<char> const&)
66
67
0
  void Assign(const nsACString& aStr) {
68
0
    NS_ASSERTION(aStr.Length() >= sHashSize,
69
0
                 "string must be at least sHashSize characters long");
70
0
    memcpy(buf, aStr.BeginReading(), sHashSize);
71
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::Assign(nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::Assign(nsTSubstring<char> const&)
72
73
0
  int Compare(const self_type& aOther) const {
74
0
    return Comparator::Compare(buf, aOther.buf);
75
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::Compare(mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator> const&) const
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::Compare(mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator> const&) const
76
77
0
  bool operator==(const self_type& aOther) const {
78
0
    return Comparator::Compare(buf, aOther.buf) == 0;
79
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::operator==(mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator> const&) const
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::operator==(mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator> const&) const
80
81
0
  bool operator!=(const self_type& aOther) const {
82
0
    return Comparator::Compare(buf, aOther.buf) != 0;
83
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::operator!=(mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator> const&) const
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::operator!=(mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator> const&) const
84
85
0
  bool operator<(const self_type& aOther) const {
86
0
    return Comparator::Compare(buf, aOther.buf) < 0;
87
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::operator<(mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator> const&) const
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::operator<(mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator> const&) const
88
89
0
  void ToString(nsACString& aStr) const {
90
0
    uint32_t len = ((sHashSize + 2) / 3) * 4;
91
0
92
0
    aStr.SetLength(len);
93
0
    PL_Base64Encode((char*)buf, sHashSize, aStr.BeginWriting());
94
0
    MOZ_ASSERT(aStr.BeginReading()[len] == '\0');
95
0
  }
96
97
0
  void ToHexString(nsACString& aStr) const {
98
0
    static const char* const lut = "0123456789ABCDEF";
99
0
    // 32 bytes is the longest hash
100
0
    size_t len = 32;
101
0
102
0
    aStr.SetCapacity(2 * len);
103
0
    for (size_t i = 0; i < len; ++i) {
104
0
      const char c = static_cast<char>(buf[i]);
105
0
      aStr.Append(lut[(c >> 4) & 0x0F]);
106
0
      aStr.Append(lut[c & 15]);
107
0
    }
108
0
  }
109
110
0
  uint32_t ToUint32() const {
111
0
    uint32_t n;
112
0
    memcpy(&n, buf, sizeof(n));
113
0
    return n;
114
0
  }
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<32u, mozilla::safebrowsing::CompletionComparator>::ToUint32() const
Unexecuted instantiation: mozilla::safebrowsing::SafebrowsingHash<4u, mozilla::safebrowsing::PrefixComparator>::ToUint32() const
115
0
  void FromUint32(uint32_t aHash) {
116
0
    memcpy(buf, &aHash, sizeof(aHash));
117
0
  }
118
};
119
120
class PrefixComparator {
121
public:
122
0
  static int Compare(const uint8_t* a, const uint8_t* b) {
123
0
      uint32_t first;
124
0
      memcpy(&first, a, sizeof(uint32_t));
125
0
126
0
      uint32_t second;
127
0
      memcpy(&second, b, sizeof(uint32_t));
128
0
129
0
      if (first > second) {
130
0
          return 1;
131
0
      } else if (first == second) {
132
0
          return 0;
133
0
      } else {
134
0
          return -1;
135
0
      }
136
0
  }
137
};
138
// Use this for 4-byte hashes
139
typedef SafebrowsingHash<PREFIX_SIZE, PrefixComparator> Prefix;
140
typedef nsTArray<Prefix> PrefixArray;
141
142
class CompletionComparator {
143
public:
144
0
  static int Compare(const uint8_t* a, const uint8_t* b) {
145
0
    return memcmp(a, b, COMPLETE_SIZE);
146
0
  }
147
};
148
// Use this for 32-byte hashes
149
typedef SafebrowsingHash<COMPLETE_SIZE, CompletionComparator> Completion;
150
typedef nsTArray<Completion> CompletionArray;
151
152
struct AddPrefix {
153
  // The truncated hash.
154
  Prefix prefix;
155
  // The chunk number to which it belongs.
156
  uint32_t addChunk;
157
158
0
  AddPrefix() : addChunk(0) {}
159
160
  // Returns the chunk number.
161
0
  uint32_t Chunk() const { return addChunk; }
162
0
  const Prefix &PrefixHash() const { return prefix; }
163
164
  template<class T>
165
0
  int Compare(const T& other) const {
166
0
    int cmp = prefix.Compare(other.PrefixHash());
167
0
    if (cmp != 0) {
168
0
      return cmp;
169
0
    }
170
0
    return addChunk - other.addChunk;
171
0
  }
Unexecuted instantiation: int mozilla::safebrowsing::AddPrefix::Compare<mozilla::safebrowsing::AddPrefix>(mozilla::safebrowsing::AddPrefix const&) const
Unexecuted instantiation: int mozilla::safebrowsing::AddPrefix::Compare<mozilla::safebrowsing::SubPrefix>(mozilla::safebrowsing::SubPrefix const&) const
172
};
173
174
struct AddComplete {
175
  Completion complete;
176
  uint32_t addChunk;
177
178
0
  AddComplete() : addChunk(0) {}
179
180
0
  uint32_t Chunk() const { return addChunk; }
181
  // The 4-byte prefix of the sha256 hash.
182
0
  uint32_t ToUint32() const { return complete.ToUint32(); }
183
  // The 32-byte sha256 hash.
184
0
  const Completion &CompleteHash() const { return complete; }
185
186
  template<class T>
187
0
  int Compare(const T& other) const {
188
0
    int cmp = complete.Compare(other.CompleteHash());
189
0
    if (cmp != 0) {
190
0
      return cmp;
191
0
    }
192
0
    return addChunk - other.addChunk;
193
0
  }
Unexecuted instantiation: int mozilla::safebrowsing::AddComplete::Compare<mozilla::safebrowsing::AddComplete>(mozilla::safebrowsing::AddComplete const&) const
Unexecuted instantiation: int mozilla::safebrowsing::AddComplete::Compare<mozilla::safebrowsing::SubComplete>(mozilla::safebrowsing::SubComplete const&) const
194
195
0
  bool operator!=(const AddComplete& aOther) const {
196
0
    if (addChunk != aOther.addChunk) {
197
0
      return true;
198
0
    }
199
0
    return complete != aOther.complete;
200
0
  }
201
};
202
203
struct SubPrefix {
204
  // The hash to subtract.
205
  Prefix prefix;
206
  // The chunk number of the add chunk to which the hash belonged.
207
  uint32_t addChunk;
208
  // The chunk number of this sub chunk.
209
  uint32_t subChunk;
210
211
0
  SubPrefix(): addChunk(0), subChunk(0) {}
212
213
0
  uint32_t Chunk() const { return subChunk; }
214
0
  uint32_t AddChunk() const { return addChunk; }
215
0
  const Prefix &PrefixHash() const { return prefix; }
216
217
  template<class T>
218
  // Returns 0 if and only if the chunks are the same in every way.
219
0
  int Compare(const T& aOther) const {
220
0
    int cmp = prefix.Compare(aOther.PrefixHash());
221
0
    if (cmp != 0)
222
0
      return cmp;
223
0
    if (addChunk != aOther.addChunk)
224
0
      return addChunk - aOther.addChunk;
225
0
    return subChunk - aOther.subChunk;
226
0
  }
227
228
  template<class T>
229
0
  int CompareAlt(const T& aOther) const {
230
0
    Prefix other;
231
0
    other.FromUint32(aOther.ToUint32());
232
0
    int cmp = prefix.Compare(other);
233
0
    if (cmp != 0)
234
0
      return cmp;
235
0
    return addChunk - aOther.addChunk;
236
0
  }
Unexecuted instantiation: int mozilla::safebrowsing::SubPrefix::CompareAlt<mozilla::safebrowsing::AddComplete>(mozilla::safebrowsing::AddComplete const&) const
Unexecuted instantiation: int mozilla::safebrowsing::SubPrefix::CompareAlt<mozilla::safebrowsing::SubComplete>(mozilla::safebrowsing::SubComplete const&) const
237
};
238
239
struct SubComplete {
240
  Completion complete;
241
  uint32_t addChunk;
242
  uint32_t subChunk;
243
244
0
  SubComplete() : addChunk(0), subChunk(0) {}
245
246
0
  uint32_t Chunk() const { return subChunk; }
247
0
  uint32_t AddChunk() const { return addChunk; }
248
0
  const Completion &CompleteHash() const { return complete; }
249
  // The 4-byte prefix of the sha256 hash.
250
0
  uint32_t ToUint32() const { return complete.ToUint32(); }
251
252
0
  int Compare(const SubComplete& aOther) const {
253
0
    int cmp = complete.Compare(aOther.complete);
254
0
    if (cmp != 0)
255
0
      return cmp;
256
0
    if (addChunk != aOther.addChunk)
257
0
      return addChunk - aOther.addChunk;
258
0
    return subChunk - aOther.subChunk;
259
0
  }
260
};
261
262
typedef FallibleTArray<AddPrefix>   AddPrefixArray;
263
typedef FallibleTArray<AddComplete> AddCompleteArray;
264
typedef FallibleTArray<SubPrefix>   SubPrefixArray;
265
typedef FallibleTArray<SubComplete> SubCompleteArray;
266
typedef FallibleTArray<Prefix>      MissPrefixArray;
267
268
/**
269
 * Compares chunks by their add chunk, then their prefix.
270
 */
271
template<class T>
272
class EntryCompare {
273
public:
274
  typedef T elem_type;
275
0
  static int Compare(const void* e1, const void* e2) {
276
0
    const elem_type* a = static_cast<const elem_type*>(e1);
277
0
    const elem_type* b = static_cast<const elem_type*>(e2);
278
0
    return a->Compare(*b);
279
0
  }
Unexecuted instantiation: mozilla::safebrowsing::EntryCompare<mozilla::safebrowsing::AddPrefix>::Compare(void const*, void const*)
Unexecuted instantiation: mozilla::safebrowsing::EntryCompare<mozilla::safebrowsing::AddComplete>::Compare(void const*, void const*)
Unexecuted instantiation: mozilla::safebrowsing::EntryCompare<mozilla::safebrowsing::SubPrefix>::Compare(void const*, void const*)
Unexecuted instantiation: mozilla::safebrowsing::EntryCompare<mozilla::safebrowsing::SubComplete>::Compare(void const*, void const*)
280
};
281
282
/**
283
 * Sort an array of store entries.  nsTArray::Sort uses Equal/LessThan
284
 * to sort, this does a single Compare so it's a bit quicker over the
285
 * large sorts we do.
286
 */
287
template<class T, class Alloc>
288
void
289
EntrySort(nsTArray_Impl<T, Alloc>& aArray)
290
0
{
291
0
  qsort(aArray.Elements(), aArray.Length(), sizeof(T),
292
0
        EntryCompare<T>::Compare);
293
0
}
Unexecuted instantiation: void mozilla::safebrowsing::EntrySort<mozilla::safebrowsing::AddPrefix, nsTArrayFallibleAllocator>(nsTArray_Impl<mozilla::safebrowsing::AddPrefix, nsTArrayFallibleAllocator>&)
Unexecuted instantiation: void mozilla::safebrowsing::EntrySort<mozilla::safebrowsing::AddComplete, nsTArrayFallibleAllocator>(nsTArray_Impl<mozilla::safebrowsing::AddComplete, nsTArrayFallibleAllocator>&)
Unexecuted instantiation: void mozilla::safebrowsing::EntrySort<mozilla::safebrowsing::SubPrefix, nsTArrayFallibleAllocator>(nsTArray_Impl<mozilla::safebrowsing::SubPrefix, nsTArrayFallibleAllocator>&)
Unexecuted instantiation: void mozilla::safebrowsing::EntrySort<mozilla::safebrowsing::SubComplete, nsTArrayFallibleAllocator>(nsTArray_Impl<mozilla::safebrowsing::SubComplete, nsTArrayFallibleAllocator>&)
294
295
template<class T, class Alloc>
296
nsresult
297
ReadTArray(nsIInputStream* aStream, nsTArray_Impl<T, Alloc>* aArray, uint32_t aNumElements)
298
0
{
299
0
  if (!aArray->SetLength(aNumElements, fallible))
300
0
    return NS_ERROR_OUT_OF_MEMORY;
301
0
302
0
  void *buffer = aArray->Elements();
303
0
  nsresult rv = NS_ReadInputStreamToBuffer(aStream, &buffer,
304
0
                                           (aNumElements * sizeof(T)));
305
0
  NS_ENSURE_SUCCESS(rv, rv);
306
0
  return NS_OK;
307
0
}
Unexecuted instantiation: nsresult mozilla::safebrowsing::ReadTArray<char, nsTArrayFallibleAllocator>(nsIInputStream*, nsTArray_Impl<char, nsTArrayFallibleAllocator>*, unsigned int)
Unexecuted instantiation: nsresult mozilla::safebrowsing::ReadTArray<unsigned char, nsTArrayFallibleAllocator>(nsIInputStream*, nsTArray_Impl<unsigned char, nsTArrayFallibleAllocator>*, unsigned int)
Unexecuted instantiation: nsresult mozilla::safebrowsing::ReadTArray<mozilla::safebrowsing::AddComplete, nsTArrayFallibleAllocator>(nsIInputStream*, nsTArray_Impl<mozilla::safebrowsing::AddComplete, nsTArrayFallibleAllocator>*, unsigned int)
Unexecuted instantiation: nsresult mozilla::safebrowsing::ReadTArray<mozilla::safebrowsing::SubComplete, nsTArrayFallibleAllocator>(nsIInputStream*, nsTArray_Impl<mozilla::safebrowsing::SubComplete, nsTArrayFallibleAllocator>*, unsigned int)
Unexecuted instantiation: nsresult mozilla::safebrowsing::ReadTArray<unsigned int, nsTArrayInfallibleAllocator>(nsIInputStream*, nsTArray_Impl<unsigned int, nsTArrayInfallibleAllocator>*, unsigned int)
308
309
template<class T, class Alloc>
310
nsresult
311
WriteTArray(nsIOutputStream* aStream, nsTArray_Impl<T, Alloc>& aArray)
312
0
{
313
0
  uint32_t written;
314
0
  return aStream->Write(reinterpret_cast<char*>(aArray.Elements()),
315
0
                        aArray.Length() * sizeof(T),
316
0
                        &written);
317
0
}
Unexecuted instantiation: nsresult mozilla::safebrowsing::WriteTArray<char, nsTArrayFallibleAllocator>(nsIOutputStream*, nsTArray_Impl<char, nsTArrayFallibleAllocator>&)
Unexecuted instantiation: nsresult mozilla::safebrowsing::WriteTArray<unsigned char, nsTArrayInfallibleAllocator>(nsIOutputStream*, nsTArray_Impl<unsigned char, nsTArrayInfallibleAllocator>&)
Unexecuted instantiation: nsresult mozilla::safebrowsing::WriteTArray<mozilla::safebrowsing::AddComplete, nsTArrayFallibleAllocator>(nsIOutputStream*, nsTArray_Impl<mozilla::safebrowsing::AddComplete, nsTArrayFallibleAllocator>&)
Unexecuted instantiation: nsresult mozilla::safebrowsing::WriteTArray<mozilla::safebrowsing::SubComplete, nsTArrayFallibleAllocator>(nsIOutputStream*, nsTArray_Impl<mozilla::safebrowsing::SubComplete, nsTArrayFallibleAllocator>&)
Unexecuted instantiation: nsresult mozilla::safebrowsing::WriteTArray<unsigned int, nsTArrayInfallibleAllocator>(nsIOutputStream*, nsTArray_Impl<unsigned int, nsTArrayInfallibleAllocator>&)
318
319
typedef nsClassHashtable<nsUint32HashKey, nsCString> PrefixStringMap;
320
321
typedef nsDataHashtable<nsCStringHashKey, int64_t> TableFreshnessMap;
322
323
typedef nsCStringHashKey FullHashString;
324
325
typedef nsDataHashtable<FullHashString, int64_t> FullHashExpiryCache;
326
327
struct CachedFullHashResponse {
328
  int64_t negativeCacheExpirySec;
329
330
  // Map contains all matches found in Fullhash response, this field might be empty.
331
  FullHashExpiryCache fullHashes;
332
333
0
  CachedFullHashResponse& operator=(const CachedFullHashResponse& aOther) {
334
0
    negativeCacheExpirySec = aOther.negativeCacheExpirySec;
335
0
336
0
    fullHashes.Clear();
337
0
    for (auto iter = aOther.fullHashes.ConstIter(); !iter.Done(); iter.Next()) {
338
0
      fullHashes.Put(iter.Key(), iter.Data());
339
0
    }
340
0
341
0
    return *this;
342
0
  }
343
344
0
  bool operator==(const CachedFullHashResponse& aOther) const {
345
0
    if (negativeCacheExpirySec != aOther.negativeCacheExpirySec ||
346
0
        fullHashes.Count() != aOther.fullHashes.Count()) {
347
0
      return false;
348
0
    }
349
0
    for (auto iter = fullHashes.ConstIter(); !iter.Done(); iter.Next()) {
350
0
      if (iter.Data() != aOther.fullHashes.Get(iter.Key())) {
351
0
        return false;
352
0
      }
353
0
    }
354
0
    return true;
355
0
  }
356
};
357
358
typedef nsClassHashtable<nsUint32HashKey, CachedFullHashResponse> FullHashResponseMap;
359
360
template<class T>
361
void
362
CopyClassHashTable(const T& aSource, T& aDestination)
363
0
{
364
0
  for (auto iter = aSource.ConstIter(); !iter.Done(); iter.Next()) {
365
0
    auto value = aDestination.LookupOrAdd(iter.Key());
366
0
    *value = *(iter.Data());
367
0
  }
368
0
}
369
370
} // namespace safebrowsing
371
} // namespace mozilla
372
373
#endif // SBEntries_h__