OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/process_util.h" | 5 #include "base/process_util.h" |
6 | 6 |
7 #include <ctype.h> | 7 #include <ctype.h> |
8 #include <dirent.h> | 8 #include <dirent.h> |
9 #include <dlfcn.h> | 9 #include <dlfcn.h> |
10 #include <errno.h> | 10 #include <errno.h> |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 CHECK(false) << "Out of memory."; | 506 CHECK(false) << "Out of memory."; |
507 } | 507 } |
508 | 508 |
509 void OnNoMemory() { | 509 void OnNoMemory() { |
510 OnNoMemorySize(0); | 510 OnNoMemorySize(0); |
511 } | 511 } |
512 | 512 |
513 } // namespace | 513 } // namespace |
514 | 514 |
515 extern "C" { | 515 extern "C" { |
516 // This code tries to make malloc failures fatal for security reasons. However, | |
517 // it breaks builds depending on fine details of the linker command line and | |
518 // the dependencies of other .so's that we pull in. So it's disabled for the | |
519 // moment. See crbug.com/31809 | |
520 // | |
521 // If enabling this, remember to reanble the tests in process_util_unittest.cc | |
522 | 516 |
523 #if 0 | |
524 #if !defined(LINUX_USE_TCMALLOC) | 517 #if !defined(LINUX_USE_TCMALLOC) |
525 | 518 |
526 typedef void* (*malloc_type)(size_t size); | 519 extern "C" { |
527 typedef void* (*valloc_type)(size_t size); | 520 void* __libc_malloc(size_t size); |
528 typedef void* (*pvalloc_type)(size_t size); | 521 void* __libc_realloc(void* ptr, size_t size); |
| 522 void* __libc_calloc(size_t nmemb, size_t size); |
| 523 void* __libc_valloc(size_t size); |
| 524 void* __libc_pvalloc(size_t size); |
| 525 void* __libc_memalign(size_t alignment, size_t size); |
| 526 } // extern "C" |
529 | 527 |
530 typedef void* (*calloc_type)(size_t nmemb, size_t size); | 528 // Overriding the system memory allocation functions: |
531 typedef void* (*realloc_type)(void *ptr, size_t size); | 529 // |
532 typedef void* (*memalign_type)(size_t boundary, size_t size); | 530 // For security reasons, we want malloc failures to be fatal. Too much code |
| 531 // doesn't check for a NULL return value from malloc and unconditionally uses |
| 532 // the resulting pointer. If the first offset that they try to access is |
| 533 // attacker controlled, then the attacker can direct the code to access any |
| 534 // part of memory. |
| 535 // |
| 536 // Thus, we define all the standard malloc functions here and mark them as |
| 537 // visibility 'default'. This means that they replace the malloc functions for |
| 538 // all Chromium code and also for all code in shared libraries. There are tests |
| 539 // for this in process_util_unittest.cc. |
| 540 // |
| 541 // If we are using tcmalloc, then the problem is moot since tcmalloc handles |
| 542 // this for us. Thus this code is in a !defined(LINUX_USE_TCMALLOC) block. |
| 543 // |
| 544 // We call the real libc functions in this code by using __libc_malloc etc. |
| 545 // Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on |
| 546 // the link order. Since ld.so needs calloc during symbol resolution, it |
| 547 // defines its own versions of several of these functions in dl-minimal.c. |
| 548 // Depending on the runtime library order, dlsym ended up giving us those |
| 549 // functions and bad things happened. See crbug.com/31809 |
| 550 // |
| 551 // This means that any code which calls __libc_* gets the raw libc versions of |
| 552 // these functions. |
533 | 553 |
534 typedef int (*posix_memalign_type)(void **memptr, size_t alignment, | |
535 size_t size); | |
536 | |
537 // Override the __libc_FOO name too. | |
538 #define DIE_ON_OOM_1(function_name) \ | 554 #define DIE_ON_OOM_1(function_name) \ |
539 _DIE_ON_OOM_1(function_name##_type, function_name) \ | 555 void* function_name(size_t) __attribute__ ((visibility("default"))); \ |
540 void* __libc_##function_name(size_t size) { \ | 556 \ |
541 return function_name(size); \ | |
542 } | |
543 | |
544 #define DIE_ON_OOM_2(function_name, arg1_type) \ | |
545 _DIE_ON_OOM_2(function_name##_type, function_name, arg1_type) \ | |
546 void* __libc_##function_name(arg1_type arg1, size_t size) { \ | |
547 return function_name(arg1, size); \ | |
548 } | |
549 | |
550 #define _DIE_ON_OOM_1(function_type, function_name) \ | |
551 void* function_name(size_t size) { \ | 557 void* function_name(size_t size) { \ |
552 static function_type original_function = \ | 558 void* ret = __libc_##function_name(size); \ |
553 reinterpret_cast<function_type>(dlsym(RTLD_NEXT, #function_name)); \ | |
554 void* ret = original_function(size); \ | |
555 if (ret == NULL && size != 0) \ | 559 if (ret == NULL && size != 0) \ |
556 OnNoMemorySize(size); \ | 560 OnNoMemorySize(size); \ |
557 return ret; \ | 561 return ret; \ |
558 } | 562 } |
559 | 563 |
560 #define _DIE_ON_OOM_2(function_type, function_name, arg1_type) \ | 564 #define DIE_ON_OOM_2(function_name, arg1_type) \ |
| 565 void* function_name(arg1_type, size_t) \ |
| 566 __attribute__ ((visibility("default"))); \ |
| 567 \ |
561 void* function_name(arg1_type arg1, size_t size) { \ | 568 void* function_name(arg1_type arg1, size_t size) { \ |
562 static function_type original_function = \ | 569 void* ret = __libc_##function_name(arg1, size); \ |
563 reinterpret_cast<function_type>(dlsym(RTLD_NEXT, #function_name)); \ | |
564 void* ret = original_function(arg1, size); \ | |
565 if (ret == NULL && size != 0) \ | 570 if (ret == NULL && size != 0) \ |
566 OnNoMemorySize(size); \ | 571 OnNoMemorySize(size); \ |
567 return ret; \ | 572 return ret; \ |
568 } | 573 } |
569 | 574 |
570 DIE_ON_OOM_1(malloc) | 575 DIE_ON_OOM_1(malloc) |
571 DIE_ON_OOM_1(valloc) | 576 DIE_ON_OOM_1(valloc) |
572 DIE_ON_OOM_1(pvalloc) | 577 DIE_ON_OOM_1(pvalloc) |
573 | 578 |
| 579 DIE_ON_OOM_2(calloc, size_t) |
574 DIE_ON_OOM_2(realloc, void*) | 580 DIE_ON_OOM_2(realloc, void*) |
575 DIE_ON_OOM_2(memalign, size_t) | 581 DIE_ON_OOM_2(memalign, size_t) |
576 | 582 |
577 // dlsym uses calloc so it has to be treated specially. http://crbug.com/28244 | 583 // posix_memalign has a unique signature and doesn't have a __libc_ variant. |
578 static void* null_calloc(size_t nmemb, size_t size) { | 584 int posix_memalign(void** ptr, size_t alignment, size_t size) |
579 return NULL; | 585 __attribute__ ((visibility("default"))); |
580 } | |
581 | 586 |
582 void* calloc(size_t nmemb, size_t size) { | |
583 static calloc_type original_function = NULL; | |
584 if (original_function == NULL) { | |
585 original_function = null_calloc; | |
586 original_function = reinterpret_cast<calloc_type>(dlsym(RTLD_NEXT, | |
587 "calloc")); | |
588 } | |
589 void* ret = original_function(nmemb, size); | |
590 if (ret == NULL && size != 0 && original_function != null_calloc) | |
591 OnNoMemorySize(size); | |
592 return ret; | |
593 } | |
594 | |
595 void* __libc_calloc(size_t nmemb, size_t size) { \ | |
596 return calloc(nmemb, size); | |
597 } | |
598 | |
599 // posix_memalign has a unique signature and doesn't have a __libc_ variant. | |
600 int posix_memalign(void** ptr, size_t alignment, size_t size) { | 587 int posix_memalign(void** ptr, size_t alignment, size_t size) { |
601 static posix_memalign_type original_function = | 588 // This will use the safe version of memalign, above. |
602 reinterpret_cast<posix_memalign_type>(dlsym(RTLD_NEXT, "posix_memalign")); | 589 *ptr = memalign(alignment, size); |
603 int ret = original_function(ptr, alignment, size); | 590 return 0; |
604 if (ret == ENOMEM) | |
605 OnNoMemorySize(size); | |
606 return ret; | |
607 } | 591 } |
608 | 592 |
609 #endif // !defined(LINUX_USE_TCMALLOC) | 593 #endif // !defined(LINUX_USE_TCMALLOC) |
610 #endif | |
611 } // extern C | 594 } // extern C |
612 | 595 |
613 void EnableTerminationOnOutOfMemory() { | 596 void EnableTerminationOnOutOfMemory() { |
614 // Set the new-out of memory handler. | 597 // Set the new-out of memory handler. |
615 std::set_new_handler(&OnNoMemory); | 598 std::set_new_handler(&OnNoMemory); |
616 // If we're using glibc's allocator, the above functions will override | 599 // If we're using glibc's allocator, the above functions will override |
617 // malloc and friends and make them die on out of memory. | 600 // malloc and friends and make them die on out of memory. |
618 } | 601 } |
619 | 602 |
620 bool AdjustOOMScore(ProcessId process, int score) { | 603 bool AdjustOOMScore(ProcessId process, int score) { |
621 if (score < 0 || score > 15) | 604 if (score < 0 || score > 15) |
622 return false; | 605 return false; |
623 | 606 |
624 FilePath oom_adj("/proc"); | 607 FilePath oom_adj("/proc"); |
625 oom_adj = oom_adj.Append(Int64ToString(process)); | 608 oom_adj = oom_adj.Append(Int64ToString(process)); |
626 oom_adj = oom_adj.AppendASCII("oom_adj"); | 609 oom_adj = oom_adj.AppendASCII("oom_adj"); |
627 | 610 |
628 if (!file_util::PathExists(oom_adj)) | 611 if (!file_util::PathExists(oom_adj)) |
629 return false; | 612 return false; |
630 | 613 |
631 std::string score_str = IntToString(score); | 614 std::string score_str = IntToString(score); |
632 return (static_cast<int>(score_str.length()) == | 615 return (static_cast<int>(score_str.length()) == |
633 file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); | 616 file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); |
634 } | 617 } |
635 | 618 |
636 } // namespace base | 619 } // namespace base |
OLD | NEW |