TestTainting.cpp (16705B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "gtest/gtest.h" 8 #include <math.h> 9 10 #include "mozilla/Array.h" 11 #include "mozilla/Tainting.h" 12 #include "nsTHashtable.h" 13 #include "nsHashKeys.h" 14 #include "nsTArray.h" 15 #include <array> 16 #include <deque> 17 #include <forward_list> 18 #include <list> 19 #include <map> 20 #include <set> 21 #include <unordered_map> 22 #include <unordered_set> 23 #include <vector> 24 25 using mozilla::Tainted; 26 27 #define EXPECTED_INT 10 28 #define EXPECTED_CHAR 'z' 29 30 static bool externalFunction(int arg) { return arg > 2; } 31 32 // ================================================================== 33 // MOZ_VALIDATE_AND_GET ============================================= 34 TEST(Tainting, moz_validate_and_get) 35 { 36 int bar; 37 int comparisonVariable = 20; 38 Tainted<int> foo = Tainted<int>(EXPECTED_INT); 39 40 bar = MOZ_VALIDATE_AND_GET(foo, foo < 20); 41 ASSERT_EQ(bar, EXPECTED_INT); 42 43 // This test is for comparison to an external variable, testing the 44 // default capture mode of the lambda used inside the macro. 45 bar = MOZ_VALIDATE_AND_GET(foo, foo < comparisonVariable); 46 ASSERT_EQ(bar, EXPECTED_INT); 47 48 bar = MOZ_VALIDATE_AND_GET( 49 foo, foo < 20, 50 "foo must be less than 20 because higher values represent decibel" 51 "levels greater than a a jet engine inside your ear."); 52 ASSERT_EQ(bar, EXPECTED_INT); 53 54 // Test an external variable with a comment. 55 bar = MOZ_VALIDATE_AND_GET(foo, foo < comparisonVariable, "Test comment"); 56 ASSERT_EQ(bar, EXPECTED_INT); 57 58 // Test an external function with a comment. 59 bar = MOZ_VALIDATE_AND_GET(foo, externalFunction(foo), "Test comment"); 60 ASSERT_EQ(bar, EXPECTED_INT); 61 62 // Lambda Tests 63 bar = 64 MOZ_VALIDATE_AND_GET(foo, ([&foo]() { return externalFunction(foo); }())); 65 ASSERT_EQ(bar, EXPECTED_INT); 66 67 // This test is for the lambda variant with a supplied assertion 68 // string. 69 bar = 70 MOZ_VALIDATE_AND_GET(foo, ([&foo]() { return externalFunction(foo); }()), 71 "This tests a comment"); 72 ASSERT_EQ(bar, EXPECTED_INT); 73 74 // This test is for the lambda variant with a captured variable 75 bar = MOZ_VALIDATE_AND_GET(foo, ([&foo, &comparisonVariable] { 76 bool intermediateResult = externalFunction(foo); 77 return intermediateResult || 78 comparisonVariable < 4; 79 }()), 80 "This tests a comment"); 81 ASSERT_EQ(bar, EXPECTED_INT); 82 83 // This test is for the lambda variant with full capture mode 84 bar = MOZ_VALIDATE_AND_GET(foo, ([&] { 85 bool intermediateResult = externalFunction(foo); 86 return intermediateResult || 87 comparisonVariable < 4; 88 }()), 89 "This tests a comment"); 90 ASSERT_EQ(bar, EXPECTED_INT); 91 92 // External lambdas 93 auto lambda1 = [](int foo) { return externalFunction(foo); }; 94 95 auto lambda2 = [&](int foo) { 96 bool intermediateResult = externalFunction(foo); 97 return intermediateResult || comparisonVariable < 4; 98 }; 99 100 // Test with an explicit capture 101 auto lambda3 = [&comparisonVariable](int foo) { 102 bool intermediateResult = externalFunction(foo); 103 return intermediateResult || comparisonVariable < 4; 104 }; 105 106 bar = MOZ_VALIDATE_AND_GET(foo, lambda1(foo)); 107 ASSERT_EQ(bar, EXPECTED_INT); 108 109 // Test with a comment 110 bar = MOZ_VALIDATE_AND_GET(foo, lambda1(foo), "Test comment."); 111 ASSERT_EQ(bar, EXPECTED_INT); 112 113 // Test with a default capture mode 114 bar = MOZ_VALIDATE_AND_GET(foo, lambda2(foo), "Test comment."); 115 ASSERT_EQ(bar, EXPECTED_INT); 116 117 bar = MOZ_VALIDATE_AND_GET(foo, lambda3(foo), "Test comment."); 118 ASSERT_EQ(bar, EXPECTED_INT); 119 120 // We can't test MOZ_VALIDATE_AND_GET failing, because that triggers 121 // a release assert. 122 } 123 124 // ================================================================== 125 // MOZ_IS_VALID ===================================================== 126 TEST(Tainting, moz_is_valid) 127 { 128 int comparisonVariable = 20; 129 Tainted<int> foo = Tainted<int>(EXPECTED_INT); 130 131 ASSERT_TRUE(MOZ_IS_VALID(foo, foo < 20)); 132 133 ASSERT_FALSE(MOZ_IS_VALID(foo, foo > 20)); 134 135 ASSERT_TRUE(MOZ_IS_VALID(foo, foo < comparisonVariable)); 136 137 ASSERT_TRUE( 138 MOZ_IS_VALID(foo, ([&foo]() { return externalFunction(foo); }()))); 139 140 ASSERT_TRUE(MOZ_IS_VALID(foo, ([&foo, &comparisonVariable]() { 141 bool intermediateResult = externalFunction(foo); 142 return intermediateResult || 143 comparisonVariable < 4; 144 }()))); 145 146 // External lambdas 147 auto lambda1 = [](int foo) { return externalFunction(foo); }; 148 149 auto lambda2 = [&](int foo) { 150 bool intermediateResult = externalFunction(foo); 151 return intermediateResult || comparisonVariable < 4; 152 }; 153 154 // Test with an explicit capture 155 auto lambda3 = [&comparisonVariable](int foo) { 156 bool intermediateResult = externalFunction(foo); 157 return intermediateResult || comparisonVariable < 4; 158 }; 159 160 ASSERT_TRUE(MOZ_IS_VALID(foo, lambda1(foo))); 161 162 ASSERT_TRUE(MOZ_IS_VALID(foo, lambda2(foo))); 163 164 ASSERT_TRUE(MOZ_IS_VALID(foo, lambda3(foo))); 165 } 166 167 // ================================================================== 168 // MOZ_VALIDATE_OR ================================================== 169 TEST(Tainting, moz_validate_or) 170 { 171 int result; 172 int comparisonVariable = 20; 173 Tainted<int> foo = Tainted<int>(EXPECTED_INT); 174 175 result = MOZ_VALIDATE_OR(foo, foo < 20, 100); 176 ASSERT_EQ(result, EXPECTED_INT); 177 178 result = MOZ_VALIDATE_OR(foo, foo > 20, 100); 179 ASSERT_EQ(result, 100); 180 181 result = MOZ_VALIDATE_OR(foo, foo < comparisonVariable, 100); 182 ASSERT_EQ(result, EXPECTED_INT); 183 184 // External lambdas 185 auto lambda1 = [](int foo) { return externalFunction(foo); }; 186 187 auto lambda2 = [&](int foo) { 188 bool intermediateResult = externalFunction(foo); 189 return intermediateResult || comparisonVariable < 4; 190 }; 191 192 // Test with an explicit capture 193 auto lambda3 = [&comparisonVariable](int foo) { 194 bool intermediateResult = externalFunction(foo); 195 return intermediateResult || comparisonVariable < 4; 196 }; 197 198 result = MOZ_VALIDATE_OR(foo, lambda1(foo), 100); 199 ASSERT_EQ(result, EXPECTED_INT); 200 201 result = MOZ_VALIDATE_OR(foo, lambda2(foo), 100); 202 ASSERT_EQ(result, EXPECTED_INT); 203 204 result = MOZ_VALIDATE_OR(foo, lambda3(foo), 100); 205 ASSERT_EQ(result, EXPECTED_INT); 206 207 result = 208 MOZ_VALIDATE_OR(foo, ([&foo]() { return externalFunction(foo); }()), 100); 209 ASSERT_EQ(result, EXPECTED_INT); 210 211 // This test is for the lambda variant with a supplied assertion 212 // string. 213 result = 214 MOZ_VALIDATE_OR(foo, ([&foo] { return externalFunction(foo); }()), 100); 215 ASSERT_EQ(result, EXPECTED_INT); 216 217 // This test is for the lambda variant with a captured variable 218 result = 219 MOZ_VALIDATE_OR(foo, ([&foo, &comparisonVariable] { 220 bool intermediateResult = externalFunction(foo); 221 return intermediateResult || comparisonVariable < 4; 222 }()), 223 100); 224 ASSERT_EQ(result, EXPECTED_INT); 225 226 // This test is for the lambda variant with full capture mode 227 result = 228 MOZ_VALIDATE_OR(foo, ([&] { 229 bool intermediateResult = externalFunction(foo); 230 return intermediateResult || comparisonVariable < 4; 231 }()), 232 100); 233 ASSERT_EQ(result, EXPECTED_INT); 234 } 235 236 // ================================================================== 237 // MOZ_FIND_AND_VALIDATE ============================================ 238 TEST(Tainting, moz_find_and_validate) 239 { 240 Tainted<int> foo = Tainted<int>(EXPECTED_INT); 241 Tainted<char> baz = Tainted<char>(EXPECTED_CHAR); 242 243 //------------------------------- 244 const mozilla::Array<int, 6> mozarrayWithFoo(0, 5, EXPECTED_INT, 15, 20, 25); 245 const mozilla::Array<int, 5> mozarrayWithoutFoo(0, 5, 15, 20, 25); 246 247 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, mozarrayWithFoo) == 248 mozarrayWithFoo[2]); 249 250 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, 251 mozarrayWithoutFoo) == nullptr); 252 253 //------------------------------- 254 class TestClass { 255 public: 256 int a; 257 int b; 258 259 TestClass(int a, int b) { 260 this->a = a; 261 this->b = b; 262 } 263 264 bool operator==(const TestClass& other) const { 265 return this->a == other.a && this->b == other.b; 266 } 267 }; 268 269 const mozilla::Array<TestClass, 5> mozarrayOfClassesWithFoo( 270 TestClass(0, 1), TestClass(2, 3), TestClass(EXPECTED_INT, EXPECTED_INT), 271 TestClass(4, 5), TestClass(6, 7)); 272 273 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE( 274 foo, foo == list_item.a && foo == list_item.b, 275 mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]); 276 277 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE( 278 foo, (foo == list_item.a && foo == list_item.b), 279 mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]); 280 281 ASSERT_TRUE( 282 *MOZ_FIND_AND_VALIDATE( 283 foo, 284 (foo == list_item.a && foo == list_item.b && externalFunction(foo)), 285 mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]); 286 287 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE( 288 foo, ([](int tainted_val, TestClass list_item) { 289 return tainted_val == list_item.a && 290 tainted_val == list_item.b; 291 }(foo, list_item)), 292 mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]); 293 294 auto lambda4 = [](int tainted_val, TestClass list_item) { 295 return tainted_val == list_item.a && tainted_val == list_item.b; 296 }; 297 298 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, lambda4(foo, list_item), 299 mozarrayOfClassesWithFoo) == 300 mozarrayOfClassesWithFoo[2]); 301 302 //------------------------------- 303 const char m[] = "m"; 304 const char o[] = "o"; 305 const char z[] = {EXPECTED_CHAR, '\0'}; 306 const char l[] = "l"; 307 const char a[] = "a"; 308 309 nsTHashtable<nsCharPtrHashKey> hashtableWithBaz; 310 hashtableWithBaz.PutEntry(m); 311 hashtableWithBaz.PutEntry(o); 312 hashtableWithBaz.PutEntry(z); 313 hashtableWithBaz.PutEntry(l); 314 hashtableWithBaz.PutEntry(a); 315 nsTHashtable<nsCharPtrHashKey> hashtableWithoutBaz; 316 hashtableWithoutBaz.PutEntry(m); 317 hashtableWithoutBaz.PutEntry(o); 318 hashtableWithoutBaz.PutEntry(l); 319 hashtableWithoutBaz.PutEntry(a); 320 321 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(baz, *list_item.GetKey() == baz, 322 hashtableWithBaz) == 323 hashtableWithBaz.GetEntry(z)); 324 325 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(baz, *list_item.GetKey() == baz, 326 hashtableWithoutBaz) == nullptr); 327 328 //------------------------------- 329 const nsTArray<int> nsTArrayWithFoo = {0, 5, EXPECTED_INT, 15, 20, 25}; 330 const nsTArray<int> nsTArrayWithoutFoo = {0, 5, 15, 20, 25}; 331 332 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, nsTArrayWithFoo) == 333 nsTArrayWithFoo[2]); 334 335 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, 336 nsTArrayWithoutFoo) == nullptr); 337 338 //------------------------------- 339 const std::array<int, 6> arrayWithFoo{0, 5, EXPECTED_INT, 15, 20, 25}; 340 const std::array<int, 5> arrayWithoutFoo{0, 5, 15, 20, 25}; 341 342 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, arrayWithFoo) == 343 arrayWithFoo[2]); 344 345 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, arrayWithoutFoo) == 346 nullptr); 347 348 //------------------------------- 349 const std::deque<int> dequeWithFoo{0, 5, EXPECTED_INT, 15, 20, 25}; 350 const std::deque<int> dequeWithoutFoo{0, 5, 15, 20, 25}; 351 352 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, dequeWithFoo) == 353 dequeWithFoo[2]); 354 355 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, dequeWithoutFoo) == 356 nullptr); 357 358 //------------------------------- 359 const std::forward_list<int> forwardWithFoo{0, 5, EXPECTED_INT, 15, 20, 25}; 360 const std::forward_list<int> forwardWithoutFoo{0, 5, 15, 20, 25}; 361 362 auto forwardListIt = forwardWithFoo.begin(); 363 std::advance(forwardListIt, 2); 364 365 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, forwardWithFoo) == 366 *forwardListIt); 367 368 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, forwardWithoutFoo) == 369 nullptr); 370 371 //------------------------------- 372 const std::list<int> listWithFoo{0, 5, EXPECTED_INT, 15, 20, 25}; 373 const std::list<int> listWithoutFoo{0, 5, 15, 20, 25}; 374 375 auto listIt = listWithFoo.begin(); 376 std::advance(listIt, 2); 377 378 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, listWithFoo) == 379 *listIt); 380 381 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, listWithoutFoo) == 382 nullptr); 383 384 //------------------------------- 385 const std::map<std::string, int> mapWithFoo{{ 386 {"zero", 0}, 387 {"five", 5}, 388 {"ten", EXPECTED_INT}, 389 {"fifteen", 15}, 390 {"twenty", 20}, 391 {"twenty-five", 25}, 392 }}; 393 const std::map<std::string, int> mapWithoutFoo{{ 394 {"zero", 0}, 395 {"five", 5}, 396 {"fifteen", 15}, 397 {"twenty", 20}, 398 {"twenty-five", 25}, 399 }}; 400 401 const auto map_it = mapWithFoo.find("ten"); 402 403 ASSERT_TRUE( 404 MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo, mapWithFoo)->second == 405 map_it->second); 406 407 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo, 408 mapWithoutFoo) == nullptr); 409 410 //------------------------------- 411 const std::set<int> setWithFoo{0, 5, EXPECTED_INT, 15, 20, 25}; 412 const std::set<int> setWithoutFoo{0, 5, 15, 20, 25}; 413 414 auto setIt = setWithFoo.find(EXPECTED_INT); 415 416 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, setWithFoo) == 417 *setIt); 418 419 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, setWithoutFoo) == 420 nullptr); 421 422 //------------------------------- 423 const std::unordered_map<std::string, int> unordermapWithFoo = { 424 {"zero", 0}, {"five", 5}, {"ten", EXPECTED_INT}, 425 {"fifteen", 15}, {"twenty", 20}, {"twenty-five", 25}, 426 }; 427 const std::unordered_map<std::string, int> unordermapWithoutFoo{{ 428 {"zero", 0}, 429 {"five", 5}, 430 {"fifteen", 15}, 431 {"twenty", 20}, 432 {"twenty-five", 25}, 433 }}; 434 435 auto unorderedMapIt = unordermapWithFoo.find("ten"); 436 437 ASSERT_TRUE( 438 MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo, unordermapWithFoo) 439 ->second == unorderedMapIt->second); 440 441 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo, 442 unordermapWithoutFoo) == nullptr); 443 444 //------------------------------- 445 const std::unordered_set<int> unorderedsetWithFoo{0, 5, EXPECTED_INT, 446 15, 20, 25}; 447 const std::unordered_set<int> unorderedsetWithoutFoo{0, 5, 15, 20, 25}; 448 449 auto unorderedSetIt = unorderedsetWithFoo.find(EXPECTED_INT); 450 451 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, 452 unorderedsetWithFoo) == *unorderedSetIt); 453 454 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, 455 unorderedsetWithoutFoo) == nullptr); 456 457 //------------------------------- 458 const std::vector<int> vectorWithFoo{0, 5, EXPECTED_INT, 15, 20, 25}; 459 const std::vector<int> vectorWithoutFoo{0, 5, 15, 20, 25}; 460 461 ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, vectorWithFoo) == 462 vectorWithFoo[2]); 463 464 ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, vectorWithoutFoo) == 465 nullptr); 466 } 467 468 // ================================================================== 469 // MOZ_NO_VALIDATE ================================================== 470 TEST(Tainting, moz_no_validate) 471 { 472 int result; 473 Tainted<int> foo = Tainted<int>(EXPECTED_INT); 474 475 result = MOZ_NO_VALIDATE( 476 foo, 477 "Value is used to match against a dictionary key in the parent." 478 "If there's no key present, there won't be a match." 479 "There is no risk of grabbing a cross-origin value from the dictionary," 480 "because the IPC actor is instatiated per-content-process and the " 481 "dictionary is not shared between actors."); 482 ASSERT_TRUE(result == EXPECTED_INT); 483 }