Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/LookupCache.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
#ifndef LookupCache_h__
7
#define LookupCache_h__
8
9
#include "Entries.h"
10
#include "nsString.h"
11
#include "nsTArray.h"
12
#include "nsCOMPtr.h"
13
#include "nsIFile.h"
14
#include "nsIFileStreams.h"
15
#include "mozilla/RefPtr.h"
16
#include "nsUrlClassifierPrefixSet.h"
17
#include "VariableLengthPrefixSet.h"
18
#include "mozilla/Logging.h"
19
#include "mozilla/TypedEnumBits.h"
20
#include "nsIUrlClassifierInfo.h"
21
22
namespace mozilla {
23
namespace safebrowsing {
24
25
0
#define MAX_HOST_COMPONENTS 5
26
0
#define MAX_PATH_COMPONENTS 4
27
28
class LookupResult {
29
public:
30
  LookupResult() : mNoise(false), mProtocolConfirmed(false),
31
                   mPartialHashLength(0), mConfirmed(false),
32
0
                   mProtocolV2(true) {}
33
34
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LookupResult);
35
36
  // The fragment that matched in the LookupCache
37
  union {
38
    Prefix fixedLengthPrefix;
39
    Completion complete;
40
  } hash;
41
42
0
  const Completion &CompleteHash() const {
43
0
    MOZ_ASSERT(!mNoise);
44
0
    return hash.complete;
45
0
  }
46
47
0
  nsCString PartialHash() const {
48
0
    MOZ_ASSERT(mPartialHashLength <= COMPLETE_SIZE);
49
0
    if (mNoise) {
50
0
      return nsCString(reinterpret_cast<const char*>(hash.fixedLengthPrefix.buf),
51
0
                       PREFIX_SIZE);
52
0
    } else {
53
0
      return nsCString(reinterpret_cast<const char*>(hash.complete.buf),
54
0
                       mPartialHashLength);
55
0
    }
56
0
  }
57
58
0
  nsAutoCString PartialHashHex() const {
59
0
    nsAutoCString hex;
60
0
    for (size_t i = 0; i < mPartialHashLength; i++) {
61
0
      hex.AppendPrintf("%.2X", hash.complete.buf[i]);
62
0
    }
63
0
    return hex;
64
0
  }
65
66
0
  bool Confirmed() const { return mConfirmed || mProtocolConfirmed; }
67
68
  // True if we have a complete match for this hash in the table.
69
0
  bool Complete() const { return mPartialHashLength == COMPLETE_SIZE; }
70
71
  // True if this is a noise entry, i.e. an extra entry
72
  // that is inserted to mask the true URL we are requesting.
73
  // Noise entries will not have a complete 256-bit hash as
74
  // they are fetched from the local 32-bit database and we
75
  // don't know the corresponding full URL.
76
  bool mNoise;
77
78
  bool mProtocolConfirmed;
79
80
  nsCString mTableName;
81
82
  uint32_t mPartialHashLength;
83
84
  // True as long as this lookup is complete and hasn't expired.
85
  bool mConfirmed;
86
87
  bool mProtocolV2;
88
private:
89
0
  ~LookupResult() {}
90
};
91
92
typedef nsTArray<RefPtr<LookupResult>> LookupResultArray;
93
94
class CacheResult {
95
public:
96
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheResult);
97
98
  enum { V2, V4 };
99
100
  virtual int Ver() const = 0;
101
  virtual bool findCompletion(const Completion& aCompletion) const = 0;
102
103
  template<typename T>
104
0
  static const T* Cast(const CacheResult* aThat) {
105
0
    return ((aThat && T::VER == aThat->Ver()) ?
106
0
      reinterpret_cast<const T*>(aThat) : nullptr);
107
0
  }
Unexecuted instantiation: mozilla::safebrowsing::CacheResultV2 const* mozilla::safebrowsing::CacheResult::Cast<mozilla::safebrowsing::CacheResultV2 const>(mozilla::safebrowsing::CacheResult const*)
Unexecuted instantiation: mozilla::safebrowsing::CacheResultV4 const* mozilla::safebrowsing::CacheResult::Cast<mozilla::safebrowsing::CacheResultV4 const>(mozilla::safebrowsing::CacheResult const*)
108
109
  nsCString table;
110
  Prefix prefix;
111
112
protected:
113
0
  virtual ~CacheResult() {}
114
};
115
116
class CacheResultV2 final : public CacheResult
117
{
118
public:
119
  static const int VER;
120
121
  // True when 'prefix' in CacheResult indicates a prefix that
122
  // cannot be completed.
123
  bool miss = false;
124
125
  // 'completion' and 'addChunk' are used when 'miss' field is false.
126
  Completion completion;
127
  uint32_t addChunk;
128
129
0
  bool operator==(const CacheResultV2& aOther) const {
130
0
    if (table != aOther.table ||
131
0
        prefix != aOther.prefix ||
132
0
        miss != aOther.miss) {
133
0
      return false;
134
0
    }
135
0
136
0
    if (miss) {
137
0
      return true;
138
0
    }
139
0
    return completion == aOther.completion && addChunk == aOther.addChunk;
140
0
  }
141
142
0
  bool findCompletion(const Completion& aCompletion) const override {
143
0
    return completion == aCompletion;
144
0
  }
145
146
0
  virtual int Ver() const override { return VER; }
147
};
148
149
class CacheResultV4 final : public CacheResult
150
{
151
public:
152
  static const int VER;
153
154
  CachedFullHashResponse response;
155
156
0
  bool operator==(const CacheResultV4& aOther) const {
157
0
    return table == aOther.table &&
158
0
           prefix == aOther.prefix &&
159
0
           response == aOther.response;
160
0
  }
161
162
0
  bool findCompletion(const Completion& aCompletion) const override {
163
0
    nsDependentCSubstring completion(
164
0
      reinterpret_cast<const char*>(aCompletion.buf), COMPLETE_SIZE);
165
0
    return response.fullHashes.Contains(completion);
166
0
  }
167
168
0
  virtual int Ver() const override { return VER; }
169
};
170
171
typedef nsTArray<RefPtr<const CacheResult>> ConstCacheResultArray;
172
173
class LookupCache {
174
public:
175
  // Check for a canonicalized IP address.
176
  static bool IsCanonicalizedIP(const nsACString& aHost);
177
178
  // take a lookup string (www.hostname.com/path/to/resource.html) and
179
  // expand it into the set of fragments that should be searched for in an
180
  // entry
181
  static nsresult GetLookupFragments(const nsACString& aSpec,
182
                                     nsTArray<nsCString>* aFragments);
183
  // Similar to GetKey(), but if the domain contains three or more components,
184
  // two keys will be returned:
185
  //  hostname.com/foo/bar -> [hostname.com]
186
  //  mail.hostname.com/foo/bar -> [hostname.com, mail.hostname.com]
187
  //  www.mail.hostname.com/foo/bar -> [hostname.com, mail.hostname.com]
188
  static nsresult GetHostKeys(const nsACString& aSpec,
189
                              nsTArray<nsCString>* aHostKeys);
190
191
  LookupCache(const nsACString& aTableName,
192
              const nsACString& aProvider,
193
              nsCOMPtr<nsIFile>& aStoreFile);
194
195
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LookupCache);
196
197
0
  const nsCString &TableName() const { return mTableName; }
198
199
  // The directory handle where we operate will
200
  // be moved away when a backup is made.
201
  nsresult UpdateRootDirHandle(nsCOMPtr<nsIFile>& aRootStoreDirectory);
202
203
  // Write data stored in lookup cache to disk.
204
  nsresult WriteFile();
205
206
0
  bool IsPrimed() const { return mPrimed; };
207
208
  // Called when update to clear expired entries.
209
  void InvalidateExpiredCacheEntries();
210
211
  // Copy fullhash cache from another LookupCache.
212
  void CopyFullHashCache(const LookupCache* aSource);
213
214
  // Clear fullhash cache from fullhash/gethash response.
215
  void ClearCache();
216
217
  // Check if completions can be found in cache.
218
  // Currently this is only used by testcase.
219
0
  bool IsInCache(uint32_t key) const { return mFullHashCache.Get(key); };
220
221
#if DEBUG
222
  void DumpCache() const;
223
#endif
224
225
  void GetCacheInfo(nsIUrlClassifierCacheInfo** aCache) const;
226
227
  virtual nsresult Open();
228
  virtual nsresult Init() = 0;
229
  virtual nsresult ClearPrefixes() = 0;
230
  virtual nsresult Has(const Completion& aCompletion,
231
                       bool* aHas,
232
                       uint32_t* aMatchLength,
233
                       bool* aConfirmed) = 0;
234
235
  virtual bool IsEmpty() const = 0;
236
237
  virtual void ClearAll();
238
239
  template<typename T>
240
0
  static T* Cast(LookupCache* aThat) {
241
0
    return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<T*>(aThat) : nullptr);
242
0
  }
Unexecuted instantiation: mozilla::safebrowsing::LookupCacheV2* mozilla::safebrowsing::LookupCache::Cast<mozilla::safebrowsing::LookupCacheV2>(mozilla::safebrowsing::LookupCache*)
Unexecuted instantiation: mozilla::safebrowsing::LookupCacheV4* mozilla::safebrowsing::LookupCache::Cast<mozilla::safebrowsing::LookupCacheV4>(mozilla::safebrowsing::LookupCache*)
243
  template<typename T>
244
0
  static const T* Cast(const LookupCache* aThat) {
245
0
    return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<const T*>(aThat) : nullptr);
246
0
  }
247
248
private:
249
  nsresult LoadPrefixSet();
250
251
  virtual nsresult StoreToFile(nsCOMPtr<nsIFile>& aFile) = 0;
252
  virtual nsresult LoadFromFile(nsCOMPtr<nsIFile>& aFile) = 0;
253
  virtual size_t SizeOfPrefixSet() const = 0;
254
255
  virtual int Ver() const = 0;
256
257
protected:
258
0
  virtual ~LookupCache() {}
259
260
  // Check completions in positive cache and prefix in negative cache.
261
  // 'aHas' and 'aConfirmed' are output parameters.
262
  nsresult CheckCache(const Completion& aCompletion,
263
                      bool* aHas,
264
                      bool* aConfirmed);
265
266
  bool mPrimed; // true when the PrefixSet has been loaded (or constructed)
267
  const nsCString mTableName;
268
  const nsCString mProvider;
269
  nsCOMPtr<nsIFile> mRootStoreDirectory;
270
  nsCOMPtr<nsIFile> mStoreDirectory;
271
272
  // For gtest to inspect private members.
273
  friend class PerProviderDirectoryTestUtils;
274
275
  // Cache stores fullhash response(V4)/gethash response(V2)
276
  FullHashResponseMap mFullHashCache;
277
};
278
279
typedef nsTArray<RefPtr<LookupCache>> LookupCacheArray;
280
281
class LookupCacheV2 final : public LookupCache
282
{
283
public:
284
  explicit LookupCacheV2(const nsACString& aTableName,
285
                         const nsACString& aProvider,
286
                         nsCOMPtr<nsIFile>& aStoreFile)
287
0
    : LookupCache(aTableName, aProvider, aStoreFile) {}
288
289
  virtual nsresult Init() override;
290
  virtual nsresult Open() override;
291
  virtual void ClearAll() override;
292
  virtual nsresult Has(const Completion& aCompletion,
293
                       bool* aHas,
294
                       uint32_t* aMatchLength,
295
                       bool* aConfirmed) override;
296
297
  virtual bool IsEmpty() const override;
298
299
  nsresult Build(AddPrefixArray& aAddPrefixes,
300
                 AddCompleteArray& aAddCompletes);
301
302
  nsresult GetPrefixes(FallibleTArray<uint32_t>& aAddPrefixes);
303
304
  // This will Clear() the passed arrays when done.
305
  // 'aExpirySec' is used by testcase to config an expired time.
306
  void AddGethashResultToCache(const AddCompleteArray& aAddCompletes,
307
                               const MissPrefixArray& aMissPrefixes,
308
                               int64_t aExpirySec = 0);
309
310
#if DEBUG
311
  void DumpCompletions() const;
312
#endif
313
314
  static const int VER;
315
316
protected:
317
  nsresult ReadCompletions();
318
319
  virtual nsresult ClearPrefixes() override;
320
  virtual nsresult StoreToFile(nsCOMPtr<nsIFile>& aFile) override;
321
  virtual nsresult LoadFromFile(nsCOMPtr<nsIFile>& aFile) override;
322
  virtual size_t SizeOfPrefixSet() const override;
323
324
private:
325
0
  ~LookupCacheV2() {}
326
327
0
  virtual int Ver() const override { return VER; }
328
329
  // Construct a Prefix Set with known prefixes.
330
  // This will Clear() aAddPrefixes when done.
331
  nsresult ConstructPrefixSet(AddPrefixArray& aAddPrefixes);
332
333
  // Full length hashes obtained in update request
334
  CompletionArray mUpdateCompletions;
335
336
  // Set of prefixes known to be in the database
337
  RefPtr<nsUrlClassifierPrefixSet> mPrefixSet;
338
};
339
340
} // namespace safebrowsing
341
} // namespace mozilla
342
343
#endif