1 //  Copyright (c) 2020-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // This file contains classes containing fields to protect individual entries.
7 // The classes are named "ProtectionInfo<suffix>", where <suffix> indicates the
8 // combination of fields that are covered. Each field has a single letter
9 // abbreviation as follows.
10 //
11 // K = key
12 // V = value
13 // O = optype aka value type
14 // S = seqno
15 // C = CF ID
16 //
17 // Then, for example, a class that protects an entry consisting of key, value,
18 // optype, and CF ID (i.e., a `WriteBatch` entry) would be named
19 // `ProtectionInfoKVOC`.
20 //
21 // The `ProtectionInfo.*` classes are templated on the integer type used to hold
22 // the XOR of hashes for each field. Only unsigned integer types are supported,
23 // and the maximum supported integer width is 64 bits. When the integer type is
24 // narrower than the hash values, we lop off the most significant bits to make
25 // them fit.
26 //
27 // The `ProtectionInfo.*` classes are all intended to be non-persistent. We do
28 // not currently make the byte order consistent for integer fields before
29 // hashing them, so the resulting values are endianness-dependent.
30 
31 #pragma once
32 
33 #include <type_traits>
34 
35 #include "db/dbformat.h"
36 #include "rocksdb/types.h"
37 #include "util/hash.h"
38 
39 namespace ROCKSDB_NAMESPACE {
40 
41 template <typename T>
42 class ProtectionInfo;
43 template <typename T>
44 class ProtectionInfoKVO;
45 template <typename T>
46 class ProtectionInfoKVOC;
47 template <typename T>
48 class ProtectionInfoKVOS;
49 
50 // Aliases for 64-bit protection infos.
51 using ProtectionInfo64 = ProtectionInfo<uint64_t>;
52 using ProtectionInfoKVO64 = ProtectionInfoKVO<uint64_t>;
53 using ProtectionInfoKVOC64 = ProtectionInfoKVOC<uint64_t>;
54 using ProtectionInfoKVOS64 = ProtectionInfoKVOS<uint64_t>;
55 
56 template <typename T>
57 class ProtectionInfo {
58  public:
59   ProtectionInfo<T>() = default;
60 
61   Status GetStatus() const;
62   ProtectionInfoKVO<T> ProtectKVO(const Slice& key, const Slice& value,
63                                   ValueType op_type) const;
64   ProtectionInfoKVO<T> ProtectKVO(const SliceParts& key,
65                                   const SliceParts& value,
66                                   ValueType op_type) const;
67 
68  private:
69   friend class ProtectionInfoKVO<T>;
70   friend class ProtectionInfoKVOS<T>;
71   friend class ProtectionInfoKVOC<T>;
72 
73   // Each field is hashed with an independent value so we can catch fields being
74   // swapped. Per the `NPHash64()` docs, using consecutive seeds is a pitfall,
75   // and we should instead vary our seeds by a large odd number. This value by
76   // which we increment (0xD28AAD72F49BD50B) was taken from
77   // `head -c8 /dev/urandom | hexdump`, run repeatedly until it yielded an odd
78   // number. The values are computed manually since the Windows C++ compiler
79   // complains about the overflow when adding constants.
80   static const uint64_t kSeedK = 0;
81   static const uint64_t kSeedV = 0xD28AAD72F49BD50B;
82   static const uint64_t kSeedO = 0xA5155AE5E937AA16;
83   static const uint64_t kSeedS = 0x77A00858DDD37F21;
84   static const uint64_t kSeedC = 0x4A2AB5CBD26F542C;
85 
val_(val)86   ProtectionInfo<T>(T val) : val_(val) {
87     static_assert(sizeof(ProtectionInfo<T>) == sizeof(T), "");
88   }
89 
GetVal()90   T GetVal() const { return val_; }
SetVal(T val)91   void SetVal(T val) { val_ = val; }
92 
93   T val_ = 0;
94 };
95 
96 template <typename T>
97 class ProtectionInfoKVO {
98  public:
99   ProtectionInfoKVO<T>() = default;
100 
101   ProtectionInfo<T> StripKVO(const Slice& key, const Slice& value,
102                              ValueType op_type) const;
103   ProtectionInfo<T> StripKVO(const SliceParts& key, const SliceParts& value,
104                              ValueType op_type) const;
105 
106   ProtectionInfoKVOC<T> ProtectC(ColumnFamilyId column_family_id) const;
107   ProtectionInfoKVOS<T> ProtectS(SequenceNumber sequence_number) const;
108 
109   void UpdateK(const Slice& old_key, const Slice& new_key);
110   void UpdateK(const SliceParts& old_key, const SliceParts& new_key);
111   void UpdateV(const Slice& old_value, const Slice& new_value);
112   void UpdateV(const SliceParts& old_value, const SliceParts& new_value);
113   void UpdateO(ValueType old_op_type, ValueType new_op_type);
114 
115  private:
116   friend class ProtectionInfo<T>;
117   friend class ProtectionInfoKVOS<T>;
118   friend class ProtectionInfoKVOC<T>;
119 
info_(val)120   explicit ProtectionInfoKVO<T>(T val) : info_(val) {
121     static_assert(sizeof(ProtectionInfoKVO<T>) == sizeof(T), "");
122   }
123 
GetVal()124   T GetVal() const { return info_.GetVal(); }
SetVal(T val)125   void SetVal(T val) { info_.SetVal(val); }
126 
127   ProtectionInfo<T> info_;
128 };
129 
130 template <typename T>
131 class ProtectionInfoKVOC {
132  public:
133   ProtectionInfoKVOC<T>() = default;
134 
135   ProtectionInfoKVO<T> StripC(ColumnFamilyId column_family_id) const;
136 
UpdateK(const Slice & old_key,const Slice & new_key)137   void UpdateK(const Slice& old_key, const Slice& new_key) {
138     kvo_.UpdateK(old_key, new_key);
139   }
UpdateK(const SliceParts & old_key,const SliceParts & new_key)140   void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
141     kvo_.UpdateK(old_key, new_key);
142   }
UpdateV(const Slice & old_value,const Slice & new_value)143   void UpdateV(const Slice& old_value, const Slice& new_value) {
144     kvo_.UpdateV(old_value, new_value);
145   }
UpdateV(const SliceParts & old_value,const SliceParts & new_value)146   void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
147     kvo_.UpdateV(old_value, new_value);
148   }
UpdateO(ValueType old_op_type,ValueType new_op_type)149   void UpdateO(ValueType old_op_type, ValueType new_op_type) {
150     kvo_.UpdateO(old_op_type, new_op_type);
151   }
152   void UpdateC(ColumnFamilyId old_column_family_id,
153                ColumnFamilyId new_column_family_id);
154 
155  private:
156   friend class ProtectionInfoKVO<T>;
157 
kvo_(val)158   explicit ProtectionInfoKVOC<T>(T val) : kvo_(val) {
159     static_assert(sizeof(ProtectionInfoKVOC<T>) == sizeof(T), "");
160   }
161 
GetVal()162   T GetVal() const { return kvo_.GetVal(); }
SetVal(T val)163   void SetVal(T val) { kvo_.SetVal(val); }
164 
165   ProtectionInfoKVO<T> kvo_;
166 };
167 
168 template <typename T>
169 class ProtectionInfoKVOS {
170  public:
171   ProtectionInfoKVOS<T>() = default;
172 
173   ProtectionInfoKVO<T> StripS(SequenceNumber sequence_number) const;
174 
UpdateK(const Slice & old_key,const Slice & new_key)175   void UpdateK(const Slice& old_key, const Slice& new_key) {
176     kvo_.UpdateK(old_key, new_key);
177   }
UpdateK(const SliceParts & old_key,const SliceParts & new_key)178   void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
179     kvo_.UpdateK(old_key, new_key);
180   }
UpdateV(const Slice & old_value,const Slice & new_value)181   void UpdateV(const Slice& old_value, const Slice& new_value) {
182     kvo_.UpdateV(old_value, new_value);
183   }
UpdateV(const SliceParts & old_value,const SliceParts & new_value)184   void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
185     kvo_.UpdateV(old_value, new_value);
186   }
UpdateO(ValueType old_op_type,ValueType new_op_type)187   void UpdateO(ValueType old_op_type, ValueType new_op_type) {
188     kvo_.UpdateO(old_op_type, new_op_type);
189   }
190   void UpdateS(SequenceNumber old_sequence_number,
191                SequenceNumber new_sequence_number);
192 
193  private:
194   friend class ProtectionInfoKVO<T>;
195 
kvo_(val)196   explicit ProtectionInfoKVOS<T>(T val) : kvo_(val) {
197     static_assert(sizeof(ProtectionInfoKVOS<T>) == sizeof(T), "");
198   }
199 
GetVal()200   T GetVal() const { return kvo_.GetVal(); }
SetVal(T val)201   void SetVal(T val) { kvo_.SetVal(val); }
202 
203   ProtectionInfoKVO<T> kvo_;
204 };
205 
206 template <typename T>
GetStatus()207 Status ProtectionInfo<T>::GetStatus() const {
208   if (val_ != 0) {
209     return Status::Corruption("ProtectionInfo mismatch");
210   }
211   return Status::OK();
212 }
213 
214 template <typename T>
ProtectKVO(const Slice & key,const Slice & value,ValueType op_type)215 ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const Slice& key,
216                                                    const Slice& value,
217                                                    ValueType op_type) const {
218   T val = GetVal();
219   val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
220   val =
221       val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
222   val = val ^
223         static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
224                                 sizeof(op_type), ProtectionInfo<T>::kSeedO));
225   return ProtectionInfoKVO<T>(val);
226 }
227 
228 template <typename T>
ProtectKVO(const SliceParts & key,const SliceParts & value,ValueType op_type)229 ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const SliceParts& key,
230                                                    const SliceParts& value,
231                                                    ValueType op_type) const {
232   T val = GetVal();
233   val = val ^
234         static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
235   val = val ^
236         static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
237   val = val ^
238         static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
239                                 sizeof(op_type), ProtectionInfo<T>::kSeedO));
240   return ProtectionInfoKVO<T>(val);
241 }
242 
243 template <typename T>
UpdateK(const Slice & old_key,const Slice & new_key)244 void ProtectionInfoKVO<T>::UpdateK(const Slice& old_key, const Slice& new_key) {
245   T val = GetVal();
246   val = val ^
247         static_cast<T>(GetSliceNPHash64(old_key, ProtectionInfo<T>::kSeedK));
248   val = val ^
249         static_cast<T>(GetSliceNPHash64(new_key, ProtectionInfo<T>::kSeedK));
250   SetVal(val);
251 }
252 
253 template <typename T>
UpdateK(const SliceParts & old_key,const SliceParts & new_key)254 void ProtectionInfoKVO<T>::UpdateK(const SliceParts& old_key,
255                                    const SliceParts& new_key) {
256   T val = GetVal();
257   val = val ^ static_cast<T>(
258                   GetSlicePartsNPHash64(old_key, ProtectionInfo<T>::kSeedK));
259   val = val ^ static_cast<T>(
260                   GetSlicePartsNPHash64(new_key, ProtectionInfo<T>::kSeedK));
261   SetVal(val);
262 }
263 
264 template <typename T>
UpdateV(const Slice & old_value,const Slice & new_value)265 void ProtectionInfoKVO<T>::UpdateV(const Slice& old_value,
266                                    const Slice& new_value) {
267   T val = GetVal();
268   val = val ^
269         static_cast<T>(GetSliceNPHash64(old_value, ProtectionInfo<T>::kSeedV));
270   val = val ^
271         static_cast<T>(GetSliceNPHash64(new_value, ProtectionInfo<T>::kSeedV));
272   SetVal(val);
273 }
274 
275 template <typename T>
UpdateV(const SliceParts & old_value,const SliceParts & new_value)276 void ProtectionInfoKVO<T>::UpdateV(const SliceParts& old_value,
277                                    const SliceParts& new_value) {
278   T val = GetVal();
279   val = val ^ static_cast<T>(
280                   GetSlicePartsNPHash64(old_value, ProtectionInfo<T>::kSeedV));
281   val = val ^ static_cast<T>(
282                   GetSlicePartsNPHash64(new_value, ProtectionInfo<T>::kSeedV));
283   SetVal(val);
284 }
285 
286 template <typename T>
UpdateO(ValueType old_op_type,ValueType new_op_type)287 void ProtectionInfoKVO<T>::UpdateO(ValueType old_op_type,
288                                    ValueType new_op_type) {
289   T val = GetVal();
290   val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&old_op_type),
291                                       sizeof(old_op_type),
292                                       ProtectionInfo<T>::kSeedO));
293   val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&new_op_type),
294                                       sizeof(new_op_type),
295                                       ProtectionInfo<T>::kSeedO));
296   SetVal(val);
297 }
298 
299 template <typename T>
StripKVO(const Slice & key,const Slice & value,ValueType op_type)300 ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const Slice& key,
301                                                  const Slice& value,
302                                                  ValueType op_type) const {
303   T val = GetVal();
304   val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
305   val =
306       val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
307   val = val ^
308         static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
309                                 sizeof(op_type), ProtectionInfo<T>::kSeedO));
310   return ProtectionInfo<T>(val);
311 }
312 
313 template <typename T>
StripKVO(const SliceParts & key,const SliceParts & value,ValueType op_type)314 ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const SliceParts& key,
315                                                  const SliceParts& value,
316                                                  ValueType op_type) const {
317   T val = GetVal();
318   val = val ^
319         static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
320   val = val ^
321         static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
322   val = val ^
323         static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
324                                 sizeof(op_type), ProtectionInfo<T>::kSeedO));
325   return ProtectionInfo<T>(val);
326 }
327 
328 template <typename T>
ProtectC(ColumnFamilyId column_family_id)329 ProtectionInfoKVOC<T> ProtectionInfoKVO<T>::ProtectC(
330     ColumnFamilyId column_family_id) const {
331   T val = GetVal();
332   val = val ^ static_cast<T>(NPHash64(
333                   reinterpret_cast<char*>(&column_family_id),
334                   sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
335   return ProtectionInfoKVOC<T>(val);
336 }
337 
338 template <typename T>
StripC(ColumnFamilyId column_family_id)339 ProtectionInfoKVO<T> ProtectionInfoKVOC<T>::StripC(
340     ColumnFamilyId column_family_id) const {
341   T val = GetVal();
342   val = val ^ static_cast<T>(NPHash64(
343                   reinterpret_cast<char*>(&column_family_id),
344                   sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
345   return ProtectionInfoKVO<T>(val);
346 }
347 
348 template <typename T>
UpdateC(ColumnFamilyId old_column_family_id,ColumnFamilyId new_column_family_id)349 void ProtectionInfoKVOC<T>::UpdateC(ColumnFamilyId old_column_family_id,
350                                     ColumnFamilyId new_column_family_id) {
351   T val = GetVal();
352   val = val ^ static_cast<T>(NPHash64(
353                   reinterpret_cast<char*>(&old_column_family_id),
354                   sizeof(old_column_family_id), ProtectionInfo<T>::kSeedC));
355   val = val ^ static_cast<T>(NPHash64(
356                   reinterpret_cast<char*>(&new_column_family_id),
357                   sizeof(new_column_family_id), ProtectionInfo<T>::kSeedC));
358   SetVal(val);
359 }
360 
361 template <typename T>
ProtectS(SequenceNumber sequence_number)362 ProtectionInfoKVOS<T> ProtectionInfoKVO<T>::ProtectS(
363     SequenceNumber sequence_number) const {
364   T val = GetVal();
365   val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
366                                       sizeof(sequence_number),
367                                       ProtectionInfo<T>::kSeedS));
368   return ProtectionInfoKVOS<T>(val);
369 }
370 
371 template <typename T>
StripS(SequenceNumber sequence_number)372 ProtectionInfoKVO<T> ProtectionInfoKVOS<T>::StripS(
373     SequenceNumber sequence_number) const {
374   T val = GetVal();
375   val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
376                                       sizeof(sequence_number),
377                                       ProtectionInfo<T>::kSeedS));
378   return ProtectionInfoKVO<T>(val);
379 }
380 
381 template <typename T>
UpdateS(SequenceNumber old_sequence_number,SequenceNumber new_sequence_number)382 void ProtectionInfoKVOS<T>::UpdateS(SequenceNumber old_sequence_number,
383                                     SequenceNumber new_sequence_number) {
384   T val = GetVal();
385   val = val ^ static_cast<T>(NPHash64(
386                   reinterpret_cast<char*>(&old_sequence_number),
387                   sizeof(old_sequence_number), ProtectionInfo<T>::kSeedS));
388   val = val ^ static_cast<T>(NPHash64(
389                   reinterpret_cast<char*>(&new_sequence_number),
390                   sizeof(new_sequence_number), ProtectionInfo<T>::kSeedS));
391   SetVal(val);
392 }
393 
394 }  // namespace ROCKSDB_NAMESPACE
395