| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 // This is the Android-specific Chromium linker, a tiny shared library | 5 // This is the Android-specific Chromium linker, a tiny shared library |
| 6 // implementing a custom dynamic linker that can be used to load the | 6 // implementing a custom dynamic linker that can be used to load the |
| 7 // real Chromium libraries (e.g. libcontentshell.so). | 7 // real Chromium libraries (e.g. libcontentshell.so). |
| 8 | 8 |
| 9 // The main point of this linker is to be able to share the RELRO | 9 // The main point of this linker is to be able to share the RELRO |
| 10 // section of libcontentshell.so (or equivalent) between the browser and | 10 // section of libcontentshell.so (or equivalent) between the browser and |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 jlong load_address, | 379 jlong load_address, |
| 380 jobject lib_info_obj) { | 380 jobject lib_info_obj) { |
| 381 String zipfile_name_str(env, zipfile_name); | 381 String zipfile_name_str(env, zipfile_name); |
| 382 String lib_name(env, library_name); | 382 String lib_name(env, library_name); |
| 383 ZipLibraryOpener opener(zipfile_name_str.c_str()); | 383 ZipLibraryOpener opener(zipfile_name_str.c_str()); |
| 384 return GenericLoadLibrary( | 384 return GenericLoadLibrary( |
| 385 env, lib_name.c_str(), | 385 env, lib_name.c_str(), |
| 386 static_cast<size_t>(load_address), lib_info_obj, opener); | 386 static_cast<size_t>(load_address), lib_info_obj, opener); |
| 387 } | 387 } |
| 388 | 388 |
| 389 // Enable the fallback due to lack of support for mapping the APK file with |
| 390 // executable permission in the crazy linker. |
| 391 // |
| 392 // |env| is the current JNI environment handle and is ignored here. |
| 393 // |clazz| is the static class handle for org.chromium.base.Linker, |
| 394 // and is ignored here. |
| 395 void EnableNoMapExecSupportFallback(JNIEnv* env, jclass clazz) { |
| 396 crazy_context_t* context = GetCrazyContext(); |
| 397 crazy_context_set_no_map_exec_support_fallback_enabled(context, true); |
| 398 } |
| 399 |
| 389 // Class holding the Java class and method ID for the Java side Linker | 400 // Class holding the Java class and method ID for the Java side Linker |
| 390 // postCallbackOnMainThread method. | 401 // postCallbackOnMainThread method. |
| 391 struct JavaCallbackBindings_class { | 402 struct JavaCallbackBindings_class { |
| 392 jclass clazz; | 403 jclass clazz; |
| 393 jmethodID method_id; | 404 jmethodID method_id; |
| 394 | 405 |
| 395 // Initialize an instance. | 406 // Initialize an instance. |
| 396 bool Init(JNIEnv* env, jclass linker_class) { | 407 bool Init(JNIEnv* env, jclass linker_class) { |
| 397 clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class)); | 408 clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class)); |
| 398 return InitStaticMethodId(env, | 409 return InitStaticMethodId(env, |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 char buffer[kMaxFilePathLengthInZip + 1]; | 602 char buffer[kMaxFilePathLengthInZip + 1]; |
| 592 if (crazy_library_file_path_in_zip_file( | 603 if (crazy_library_file_path_in_zip_file( |
| 593 lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) { | 604 lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) { |
| 594 LOG_ERROR("%s: Failed to get full filename for library '%s'", | 605 LOG_ERROR("%s: Failed to get full filename for library '%s'", |
| 595 __FUNCTION__, lib_name_c_str); | 606 __FUNCTION__, lib_name_c_str); |
| 596 buffer[0] = '\0'; | 607 buffer[0] = '\0'; |
| 597 } | 608 } |
| 598 return env->NewStringUTF(buffer); | 609 return env->NewStringUTF(buffer); |
| 599 } | 610 } |
| 600 | 611 |
| 601 // Check whether the device supports loading a library directly from the APK | 612 // Check whether the device supports mapping the APK file with executable |
| 602 // file. | 613 // permission. |
| 603 // | 614 // |
| 604 // |env| is the current JNI environment handle. | 615 // |env| is the current JNI environment handle. |
| 605 // |clazz| is the static class handle which is not used here. | 616 // |clazz| is the static class handle which is not used here. |
| 606 // |apkfile_name| is the filename of the APK. | 617 // |apkfile_name| is the filename of the APK. |
| 607 // Returns true if supported. | 618 // Returns true if supported. |
| 608 jboolean CheckLibraryLoadFromApkSupport(JNIEnv* env, jclass clazz, | 619 jboolean CheckMapExecSupport(JNIEnv* env, jclass clazz, jstring apkfile_name) { |
| 609 jstring apkfile_name) { | |
| 610 String apkfile_name_str(env, apkfile_name); | 620 String apkfile_name_str(env, apkfile_name); |
| 611 const char* apkfile_name_c_str = apkfile_name_str.c_str(); | 621 const char* apkfile_name_c_str = apkfile_name_str.c_str(); |
| 612 | 622 |
| 613 int fd = open(apkfile_name_c_str, O_RDONLY); | 623 int fd = open(apkfile_name_c_str, O_RDONLY); |
| 614 if (fd == -1) { | 624 if (fd == -1) { |
| 615 LOG_ERROR("%s: Failed to open %s\n", __FUNCTION__, apkfile_name_c_str); | 625 LOG_ERROR("%s: Failed to open %s\n", __FUNCTION__, apkfile_name_c_str); |
| 616 return false; | 626 return false; |
| 617 } | 627 } |
| 618 | 628 |
| 619 LOG_INFO( | 629 LOG_INFO( |
| 620 "%s: Memory mapping the first page of %s with executable permissions\n", | 630 "%s: Memory mapping the first page of %s with executable permissions\n", |
| 621 __FUNCTION__, apkfile_name_c_str); | 631 __FUNCTION__, apkfile_name_c_str); |
| 622 void* address = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_PRIVATE, fd, 0); | 632 void* address = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_PRIVATE, fd, 0); |
| 623 | 633 |
| 624 jboolean status; | 634 jboolean status; |
| 625 if (address == MAP_FAILED) { | 635 if (address == MAP_FAILED) { |
| 626 status = false; | 636 status = false; |
| 627 } else { | 637 } else { |
| 628 status = true; | 638 status = true; |
| 629 munmap(address, PAGE_SIZE); | 639 munmap(address, PAGE_SIZE); |
| 630 } | 640 } |
| 631 | 641 |
| 632 close(fd); | 642 close(fd); |
| 633 | 643 |
| 634 LOG_INFO("%s: %s\n", __FUNCTION__, status ? "Supported" : "NOT supported"); | 644 LOG_INFO("%s: %s\n", __FUNCTION__, status ? "Supported" : "NOT supported"); |
| 635 return status; | 645 return status; |
| 636 } | 646 } |
| 637 | 647 |
| 638 // Check whether a library is page aligned in the APK file. | 648 // Check whether a library is page aligned and uncompressed in the APK file. |
| 639 // | 649 // |
| 640 // |env| is the current JNI environment handle. | 650 // |env| is the current JNI environment handle. |
| 641 // |clazz| is the static class handle which is not used here. | 651 // |clazz| is the static class handle which is not used here. |
| 642 // |apkfile_name| is the filename of the APK. | 652 // |apkfile_name| is the filename of the APK. |
| 643 // |library_name| is the library base name. | 653 // |library_name| is the library base name. |
| 644 // Returns true if page aligned. | 654 // Returns true if page aligned and uncompressed. |
| 645 jboolean CheckLibraryAlignedInApk(JNIEnv* env, jclass clazz, | 655 jboolean CheckLibraryIsMappableInApk(JNIEnv* env, jclass clazz, |
| 646 jstring apkfile_name, jstring library_name) { | 656 jstring apkfile_name, |
| 657 jstring library_name) { |
| 647 String apkfile_name_str(env, apkfile_name); | 658 String apkfile_name_str(env, apkfile_name); |
| 648 const char* apkfile_name_c_str = apkfile_name_str.c_str(); | 659 const char* apkfile_name_c_str = apkfile_name_str.c_str(); |
| 649 String library_name_str(env, library_name); | 660 String library_name_str(env, library_name); |
| 650 const char* library_name_c_str = library_name_str.c_str(); | 661 const char* library_name_c_str = library_name_str.c_str(); |
| 651 | 662 |
| 652 LOG_INFO("%s: Checking if %s is page-aligned in %s\n", __FUNCTION__, | 663 LOG_INFO("%s: Checking if %s is page-aligned and uncompressed in %s\n", |
| 653 library_name_c_str, apkfile_name_c_str); | 664 __FUNCTION__, library_name_c_str, apkfile_name_c_str); |
| 654 jboolean aligned = crazy_linker_check_library_aligned_in_zip_file( | 665 jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file( |
| 655 apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS; | 666 apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS; |
| 656 LOG_INFO("%s: %s\n", __FUNCTION__, aligned ? "Aligned" : "NOT aligned"); | 667 LOG_INFO("%s: %s\n", __FUNCTION__, aligned ? "Aligned" : "NOT aligned"); |
| 657 | 668 |
| 658 return aligned; | 669 return mappable; |
| 659 } | 670 } |
| 660 | 671 |
| 661 const JNINativeMethod kNativeMethods[] = { | 672 const JNINativeMethod kNativeMethods[] = { |
| 662 {"nativeLoadLibrary", | 673 {"nativeLoadLibrary", |
| 663 "(" | 674 "(" |
| 664 "Ljava/lang/String;" | 675 "Ljava/lang/String;" |
| 665 "J" | 676 "J" |
| 666 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 677 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
| 667 ")" | 678 ")" |
| 668 "Z", | 679 "Z", |
| 669 reinterpret_cast<void*>(&LoadLibrary)}, | 680 reinterpret_cast<void*>(&LoadLibrary)}, |
| 670 {"nativeLoadLibraryInZipFile", | 681 {"nativeLoadLibraryInZipFile", |
| 671 "(" | 682 "(" |
| 672 "Ljava/lang/String;" | 683 "Ljava/lang/String;" |
| 673 "Ljava/lang/String;" | 684 "Ljava/lang/String;" |
| 674 "J" | 685 "J" |
| 675 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 686 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
| 676 ")" | 687 ")" |
| 677 "Z", | 688 "Z", |
| 678 reinterpret_cast<void*>(&LoadLibraryInZipFile)}, | 689 reinterpret_cast<void*>(&LoadLibraryInZipFile)}, |
| 690 {"nativeEnableNoMapExecSupportFallback", |
| 691 "(" |
| 692 ")" |
| 693 "V", |
| 694 reinterpret_cast<void*>(&EnableNoMapExecSupportFallback)}, |
| 679 {"nativeRunCallbackOnUiThread", | 695 {"nativeRunCallbackOnUiThread", |
| 680 "(" | 696 "(" |
| 681 "J" | 697 "J" |
| 682 ")" | 698 ")" |
| 683 "V", | 699 "V", |
| 684 reinterpret_cast<void*>(&RunCallbackOnUiThread)}, | 700 reinterpret_cast<void*>(&RunCallbackOnUiThread)}, |
| 685 {"nativeCreateSharedRelro", | 701 {"nativeCreateSharedRelro", |
| 686 "(" | 702 "(" |
| 687 "Ljava/lang/String;" | 703 "Ljava/lang/String;" |
| 688 "J" | 704 "J" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 707 "J" | 723 "J" |
| 708 ")" | 724 ")" |
| 709 "J", | 725 "J", |
| 710 reinterpret_cast<void*>(&GetRandomBaseLoadAddress)}, | 726 reinterpret_cast<void*>(&GetRandomBaseLoadAddress)}, |
| 711 {"nativeGetLibraryFilePathInZipFile", | 727 {"nativeGetLibraryFilePathInZipFile", |
| 712 "(" | 728 "(" |
| 713 "Ljava/lang/String;" | 729 "Ljava/lang/String;" |
| 714 ")" | 730 ")" |
| 715 "Ljava/lang/String;", | 731 "Ljava/lang/String;", |
| 716 reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)}, | 732 reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)}, |
| 717 {"nativeCheckLibraryLoadFromApkSupport", | 733 {"nativeCheckMapExecSupport", |
| 718 "(" | 734 "(" |
| 719 "Ljava/lang/String;" | 735 "Ljava/lang/String;" |
| 720 ")" | 736 ")" |
| 721 "Z", | 737 "Z", |
| 722 reinterpret_cast<void*>(&CheckLibraryLoadFromApkSupport)}, | 738 reinterpret_cast<void*>(&CheckMapExecSupport)}, |
| 723 {"nativeCheckLibraryAlignedInApk", | 739 {"nativeCheckLibraryIsMappableInApk", |
| 724 "(" | 740 "(" |
| 725 "Ljava/lang/String;" | 741 "Ljava/lang/String;" |
| 726 "Ljava/lang/String;" | 742 "Ljava/lang/String;" |
| 727 ")" | 743 ")" |
| 728 "Z", | 744 "Z", |
| 729 reinterpret_cast<void*>(&CheckLibraryAlignedInApk)}, }; | 745 reinterpret_cast<void*>(&CheckLibraryIsMappableInApk)}, }; |
| 730 | 746 |
| 731 } // namespace | 747 } // namespace |
| 732 | 748 |
| 733 // JNI_OnLoad() hook called when the linker library is loaded through | 749 // JNI_OnLoad() hook called when the linker library is loaded through |
| 734 // the regular System.LoadLibrary) API. This shall save the Java VM | 750 // the regular System.LoadLibrary) API. This shall save the Java VM |
| 735 // handle and initialize LibInfo fields. | 751 // handle and initialize LibInfo fields. |
| 736 jint JNI_OnLoad(JavaVM* vm, void* reserved) { | 752 jint JNI_OnLoad(JavaVM* vm, void* reserved) { |
| 737 LOG_INFO("%s: Entering", __FUNCTION__); | 753 LOG_INFO("%s: Entering", __FUNCTION__); |
| 738 // Get new JNIEnv | 754 // Get new JNIEnv |
| 739 JNIEnv* env; | 755 JNIEnv* env; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 770 crazy_context_t* context = GetCrazyContext(); | 786 crazy_context_t* context = GetCrazyContext(); |
| 771 crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); | 787 crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); |
| 772 | 788 |
| 773 // Register the function that the crazy linker can call to post code | 789 // Register the function that the crazy linker can call to post code |
| 774 // for later execution. | 790 // for later execution. |
| 775 crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL); | 791 crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL); |
| 776 | 792 |
| 777 LOG_INFO("%s: Done", __FUNCTION__); | 793 LOG_INFO("%s: Done", __FUNCTION__); |
| 778 return JNI_VERSION_1_4; | 794 return JNI_VERSION_1_4; |
| 779 } | 795 } |
| OLD | NEW |