 Chromium Code Reviews
 Chromium Code Reviews Issue 213693005:
  [Android] Block access to java.lang.Object.getClass in injected Java objects  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 213693005:
  [Android] Block access to java.lang.Object.getClass in injected Java objects  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/renderer_host/java/java_bound_object.h" | 5 #include "content/browser/renderer_host/java/java_bound_object.h" | 
| 6 | 6 | 
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" | 
| 8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" | 
| 9 #include "base/memory/singleton.h" | 9 #include "base/memory/singleton.h" | 
| 10 #include "base/numerics/safe_conversions.h" | 10 #include "base/numerics/safe_conversions.h" | 
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 // Note that in some cases, we differ from from the spec in order to maintain | 32 // Note that in some cases, we differ from from the spec in order to maintain | 
| 33 // existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may | 33 // existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may | 
| 34 // revisit this decision in the future. | 34 // revisit this decision in the future. | 
| 35 | 35 | 
| 36 namespace content { | 36 namespace content { | 
| 37 namespace { | 37 namespace { | 
| 38 | 38 | 
| 39 const char kJavaLangClass[] = "java/lang/Class"; | 39 const char kJavaLangClass[] = "java/lang/Class"; | 
| 40 const char kJavaLangObject[] = "java/lang/Object"; | 40 const char kJavaLangObject[] = "java/lang/Object"; | 
| 41 const char kJavaLangReflectMethod[] = "java/lang/reflect/Method"; | 41 const char kJavaLangReflectMethod[] = "java/lang/reflect/Method"; | 
| 42 const char kJavaLangSecurityExceptionClass[] = "java/lang/SecurityException"; | |
| 42 const char kGetClass[] = "getClass"; | 43 const char kGetClass[] = "getClass"; | 
| 43 const char kGetMethods[] = "getMethods"; | 44 const char kGetMethods[] = "getMethods"; | 
| 44 const char kIsAnnotationPresent[] = "isAnnotationPresent"; | 45 const char kIsAnnotationPresent[] = "isAnnotationPresent"; | 
| 45 const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; | 46 const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; | 
| 46 const char kReturningJavaLangReflectMethodArray[] = | 47 const char kReturningJavaLangReflectMethodArray[] = | 
| 47 "()[Ljava/lang/reflect/Method;"; | 48 "()[Ljava/lang/reflect/Method;"; | 
| 48 const char kTakesJavaLangClassReturningBoolean[] = "(Ljava/lang/Class;)Z"; | 49 const char kTakesJavaLangClassReturningBoolean[] = "(Ljava/lang/Class;)Z"; | 
| 50 // This is an exception message, so no need to localize. | |
| 51 const char kAccessToObjectGetClassIsBlocked[] = | |
| 52 "Access to java.lang.Object.getClass is blocked"; | |
| 
palmer
2014/04/03 21:53:58
Nit: As you think of more bad classes/methods to b
 
mnaganov (inactive)
2014/04/04 10:16:49
As I have explained in the bug, so far 'getClass'
 | |
| 49 | 53 | 
| 50 // Our special NPObject type. We extend an NPObject with a pointer to a | 54 // Our special NPObject type. We extend an NPObject with a pointer to a | 
| 51 // JavaBoundObject. We also add static methods for each of the NPObject | 55 // JavaBoundObject. We also add static methods for each of the NPObject | 
| 52 // callbacks, which are registered by our NPClass. These methods simply | 56 // callbacks, which are registered by our NPClass. These methods simply | 
| 53 // delegate to the private implementation methods of JavaBoundObject. | 57 // delegate to the private implementation methods of JavaBoundObject. | 
| 54 struct JavaNPObject : public NPObject { | 58 struct JavaNPObject : public NPObject { | 
| 55 JavaBoundObject* bound_object; | 59 JavaBoundObject* bound_object; | 
| 56 | 60 | 
| 57 static const NPClass kNPClass; | 61 static const NPClass kNPClass; | 
| 58 | 62 | 
| (...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 813 } | 817 } | 
| 814 | 818 | 
| 815 JavaBoundObject::JavaBoundObject( | 819 JavaBoundObject::JavaBoundObject( | 
| 816 const JavaRef<jobject>& object, | 820 const JavaRef<jobject>& object, | 
| 817 const JavaRef<jclass>& safe_annotation_clazz, | 821 const JavaRef<jclass>& safe_annotation_clazz, | 
| 818 const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager, | 822 const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager, | 
| 819 bool can_enumerate_methods) | 823 bool can_enumerate_methods) | 
| 820 : java_object_(AttachCurrentThread(), object.obj()), | 824 : java_object_(AttachCurrentThread(), object.obj()), | 
| 821 manager_(manager), | 825 manager_(manager), | 
| 822 are_methods_set_up_(false), | 826 are_methods_set_up_(false), | 
| 827 object_get_class_method_id_(NULL), | |
| 823 can_enumerate_methods_(can_enumerate_methods), | 828 can_enumerate_methods_(can_enumerate_methods), | 
| 824 safe_annotation_clazz_(safe_annotation_clazz) { | 829 safe_annotation_clazz_(safe_annotation_clazz) { | 
| 825 BrowserThread::PostTask( | 830 BrowserThread::PostTask( | 
| 826 BrowserThread::UI, FROM_HERE, | 831 BrowserThread::UI, FROM_HERE, | 
| 827 base::Bind(&JavaBridgeDispatcherHostManager::JavaBoundObjectCreated, | 832 base::Bind(&JavaBridgeDispatcherHostManager::JavaBoundObjectCreated, | 
| 828 manager_, | 833 manager_, | 
| 829 base::android::ScopedJavaGlobalRef<jobject>(object))); | 834 base::android::ScopedJavaGlobalRef<jobject>(object))); | 
| 830 // Other than informing the JavaBridgeDispatcherHostManager that a java bound | 835 // Other than informing the JavaBridgeDispatcherHostManager that a java bound | 
| 831 // object has been created (above), we don't do anything else with our Java | 836 // object has been created (above), we don't do anything else with our Java | 
| 832 // object when first created. We do it all lazily when a method is first | 837 // object when first created. We do it all lazily when a method is first | 
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 889 } | 894 } | 
| 890 | 895 | 
| 891 // Coerce | 896 // Coerce | 
| 892 std::vector<jvalue> parameters(arg_count); | 897 std::vector<jvalue> parameters(arg_count); | 
| 893 for (size_t i = 0; i < arg_count; ++i) { | 898 for (size_t i = 0; i < arg_count; ++i) { | 
| 894 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], | 899 parameters[i] = CoerceJavaScriptValueToJavaValue(args[i], | 
| 895 method->parameter_type(i), | 900 method->parameter_type(i), | 
| 896 true); | 901 true); | 
| 897 } | 902 } | 
| 898 | 903 | 
| 899 ScopedJavaLocalRef<jobject> obj = java_object_.get(AttachCurrentThread()); | 904 JNIEnv* env = AttachCurrentThread(); | 
| 905 ScopedJavaLocalRef<jobject> obj = java_object_.get(env); | |
| 906 | |
| 907 // Block access to java.lang.Object.getClass. | |
| 908 // As it is declared to be final, it is sufficient to compare methodIDs. | |
| 909 if (method->id() == object_get_class_method_id_) { | |
| 910 BrowserThread::PostTask( | |
| 911 BrowserThread::UI, FROM_HERE, | |
| 912 base::Bind(&JavaBoundObject::ThrowSecurityException, | |
| 913 kAccessToObjectGetClassIsBlocked)); | |
| 914 return false; | |
| 915 } | |
| 900 | 916 | 
| 901 bool ok = false; | 917 bool ok = false; | 
| 902 if (!obj.is_null()) { | 918 if (!obj.is_null()) { | 
| 903 // Call | 919 // Call | 
| 904 ok = CallJNIMethod(obj.obj(), method->return_type(), | 920 ok = CallJNIMethod(obj.obj(), method->return_type(), | 
| 905 method->id(), ¶meters[0], result, | 921 method->id(), ¶meters[0], result, | 
| 906 safe_annotation_clazz_, | 922 safe_annotation_clazz_, | 
| 907 manager_, | 923 manager_, | 
| 908 can_enumerate_methods_); | 924 can_enumerate_methods_); | 
| 909 } | 925 } | 
| 910 | 926 | 
| 911 // Now that we're done with the jvalue, release any local references created | 927 // Now that we're done with the jvalue, release any local references created | 
| 912 // by CoerceJavaScriptValueToJavaValue(). | 928 // by CoerceJavaScriptValueToJavaValue(). | 
| 913 JNIEnv* env = AttachCurrentThread(); | |
| 914 for (size_t i = 0; i < arg_count; ++i) { | 929 for (size_t i = 0; i < arg_count; ++i) { | 
| 915 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); | 930 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); | 
| 916 } | 931 } | 
| 917 | 932 | 
| 918 return ok; | 933 return ok; | 
| 919 } | 934 } | 
| 920 | 935 | 
| 921 void JavaBoundObject::EnsureMethodsAreSetUp() const { | 936 void JavaBoundObject::EnsureMethodsAreSetUp() const { | 
| 922 if (are_methods_set_up_) | 937 if (are_methods_set_up_) | 
| 923 return; | 938 return; | 
| 924 are_methods_set_up_ = true; | 939 are_methods_set_up_ = true; | 
| 925 | 940 | 
| 926 JNIEnv* env = AttachCurrentThread(); | 941 JNIEnv* env = AttachCurrentThread(); | 
| 942 | |
| 943 object_get_class_method_id_ = GetMethodIDFromClassName( | |
| 944 env, | |
| 945 kJavaLangObject, | |
| 946 kGetClass, | |
| 947 kReturningJavaLangClass); | |
| 948 | |
| 927 ScopedJavaLocalRef<jobject> obj = java_object_.get(env); | 949 ScopedJavaLocalRef<jobject> obj = java_object_.get(env); | 
| 928 | 950 | 
| 929 if (obj.is_null()) { | 951 if (obj.is_null()) { | 
| 930 return; | 952 return; | 
| 931 } | 953 } | 
| 932 | 954 | 
| 933 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( | 955 ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>( | 
| 934 env->CallObjectMethod(obj.obj(), GetMethodIDFromClassName( | 956 env->CallObjectMethod(obj.obj(), object_get_class_method_id_))); | 
| 935 env, | |
| 936 kJavaLangObject, | |
| 937 kGetClass, | |
| 938 kReturningJavaLangClass)))); | |
| 939 | 957 | 
| 940 ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>( | 958 ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>( | 
| 941 env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName( | 959 env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName( | 
| 942 env, | 960 env, | 
| 943 kJavaLangClass, | 961 kJavaLangClass, | 
| 944 kGetMethods, | 962 kGetMethods, | 
| 945 kReturningJavaLangReflectMethodArray)))); | 963 kReturningJavaLangReflectMethodArray)))); | 
| 946 | 964 | 
| 947 size_t num_methods = env->GetArrayLength(methods.obj()); | 965 size_t num_methods = env->GetArrayLength(methods.obj()); | 
| 948 // Java objects always have public methods. | 966 // Java objects always have public methods. | 
| (...skipping 15 matching lines...) Expand all Loading... | |
| 964 | 982 | 
| 965 if (!safe) | 983 if (!safe) | 
| 966 continue; | 984 continue; | 
| 967 } | 985 } | 
| 968 | 986 | 
| 969 JavaMethod* method = new JavaMethod(java_method); | 987 JavaMethod* method = new JavaMethod(java_method); | 
| 970 methods_.insert(std::make_pair(method->name(), method)); | 988 methods_.insert(std::make_pair(method->name(), method)); | 
| 971 } | 989 } | 
| 972 } | 990 } | 
| 973 | 991 | 
| 992 // static | |
| 993 void JavaBoundObject::ThrowSecurityException(const char* message) { | |
| 994 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 995 JNIEnv* env = AttachCurrentThread(); | |
| 996 base::android::ScopedJavaLocalRef<jclass> clazz( | |
| 997 env, env->FindClass(kJavaLangSecurityExceptionClass)); | |
| 998 env->ThrowNew(clazz.obj(), message); | |
| 999 } | |
| 1000 | |
| 974 } // namespace content | 1001 } // namespace content | 
| OLD | NEW |