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