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 |