Add access checks to Method and Field reflection.
Art side of this change. Has a corresponding libcore change.
Bug: 13620925
Change-Id: Ie67f802a2a400e8212b489b9a261b7028422d8ba
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 48b58bf..755708e 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -20,6 +20,7 @@
#include "dex_file-inl.h"
#include "jni_internal.h"
#include "mirror/art_field-inl.h"
+#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "object_utils.h"
#include "reflection.h"
@@ -27,6 +28,21 @@
namespace art {
+static bool ValidateFieldAccess(mirror::ArtField* field, mirror::Object* obj, bool is_set)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (field->IsFinal() && is_set) {
+ ThrowIllegalAccessException(nullptr, StringPrintf("Cannot set final field: %s",
+ PrettyField(field).c_str()).c_str());
+ return false;
+ }
+ if (!ValidateAccess(obj, field->GetDeclaringClass(), field->GetAccessFlags())) {
+ ThrowIllegalAccessException(nullptr, StringPrintf("Cannot access field: %s",
+ PrettyField(field).c_str()).c_str());
+ return false;
+ }
+ return true;
+}
+
static bool GetFieldValue(const ScopedFastNativeObjectAccess& soa, mirror::Object* o,
mirror::ArtField* f, Primitive::Type field_type, bool allow_references,
JValue* value)
@@ -98,7 +114,7 @@
return true;
}
-static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
+static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
ScopedFastNativeObjectAccess soa(env);
CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization";
mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
@@ -107,6 +123,11 @@
DCHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
+ // Validate access.
+ if (!accessible && !ValidateFieldAccess(f, o, false)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
+ }
// We now don't expect suspension unless an exception is thrown.
// Get the field's value, boxing if necessary.
Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType();
@@ -119,7 +140,7 @@
}
static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj,
- char dst_descriptor) {
+ char dst_descriptor, jboolean accessible) {
ScopedFastNativeObjectAccess soa(env);
CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization";
mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
@@ -128,6 +149,13 @@
DCHECK(soa.Self()->IsExceptionPending());
return JValue();
}
+
+ // Validate access.
+ if (!accessible && !ValidateFieldAccess(f, o, false)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return JValue();
+ }
+
// We now don't expect suspension unless an exception is thrown.
// Read the value.
Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType();
@@ -147,36 +175,38 @@
return wide_value;
}
-static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'Z').GetZ();
+static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj,
+ jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'Z', accessible).GetZ();
}
-static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'B').GetB();
+static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'B', accessible).GetB();
}
-static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'C').GetC();
+static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'C', accessible).GetC();
}
-static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'D').GetD();
+static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj,
+ jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'D', accessible).GetD();
}
-static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'F').GetF();
+static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'F', accessible).GetF();
}
-static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'I').GetI();
+static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'I', accessible).GetI();
}
-static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'J').GetJ();
+static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'J', accessible).GetJ();
}
-static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) {
- return GetPrimitiveField(env, javaField, javaObj, 'S').GetS();
+static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) {
+ return GetPrimitiveField(env, javaField, javaObj, 'S', accessible).GetS();
}
static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o,
@@ -223,7 +253,8 @@
}
}
-static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
+static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue,
+ jboolean accessible) {
ScopedFastNativeObjectAccess soa(env);
CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization";
mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
@@ -260,11 +291,16 @@
DCHECK(soa.Self()->IsExceptionPending());
return;
}
+ // Validate access.
+ if (!accessible && !ValidateFieldAccess(f, o, true)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return;
+ }
SetFieldValue(soa, o, f, field_prim_type, true, unboxed_value);
}
static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor,
- const JValue& new_value) {
+ const JValue& new_value, jboolean accessible) {
ScopedFastNativeObjectAccess soa(env);
mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
mirror::Object* o = nullptr;
@@ -286,77 +322,91 @@
return;
}
+ // Validate access.
+ if (!accessible && !ValidateFieldAccess(f, o, true)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return;
+ }
+
// Write the value.
SetFieldValue(soa, o, f, field_type, false, wide_value);
}
-static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) {
+static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z,
+ jboolean accessible) {
JValue value;
value.SetZ(z);
- SetPrimitiveField(env, javaField, javaObj, 'Z', value);
+ SetPrimitiveField(env, javaField, javaObj, 'Z', value, accessible);
}
-static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b) {
+static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b,
+ jboolean accessible) {
JValue value;
value.SetB(b);
- SetPrimitiveField(env, javaField, javaObj, 'B', value);
+ SetPrimitiveField(env, javaField, javaObj, 'B', value, accessible);
}
-static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c) {
+static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c,
+ jboolean accessible) {
JValue value;
value.SetC(c);
- SetPrimitiveField(env, javaField, javaObj, 'C', value);
+ SetPrimitiveField(env, javaField, javaObj, 'C', value, accessible);
}
-static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d) {
+static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d,
+ jboolean accessible) {
JValue value;
value.SetD(d);
- SetPrimitiveField(env, javaField, javaObj, 'D', value);
+ SetPrimitiveField(env, javaField, javaObj, 'D', value, accessible);
}
-static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f) {
+static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f,
+ jboolean accessible) {
JValue value;
value.SetF(f);
- SetPrimitiveField(env, javaField, javaObj, 'F', value);
+ SetPrimitiveField(env, javaField, javaObj, 'F', value, accessible);
}
-static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i) {
+static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i,
+ jboolean accessible) {
JValue value;
value.SetI(i);
- SetPrimitiveField(env, javaField, javaObj, 'I', value);
+ SetPrimitiveField(env, javaField, javaObj, 'I', value, accessible);
}
-static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j) {
+static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j,
+ jboolean accessible) {
JValue value;
value.SetJ(j);
- SetPrimitiveField(env, javaField, javaObj, 'J', value);
+ SetPrimitiveField(env, javaField, javaObj, 'J', value, accessible);
}
-static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s) {
+static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s,
+ jboolean accessible) {
JValue value;
value.SetS(s);
- SetPrimitiveField(env, javaField, javaObj, 'S', value);
+ SetPrimitiveField(env, javaField, javaObj, 'S', value, accessible);
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Field, get, "!(Ljava/lang/Object;)Ljava/lang/Object;"),
- NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;)Z"),
- NATIVE_METHOD(Field, getByte, "!(Ljava/lang/Object;)B"),
- NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;)C"),
- NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;)D"),
- NATIVE_METHOD(Field, getFloat, "!(Ljava/lang/Object;)F"),
- NATIVE_METHOD(Field, getInt, "!(Ljava/lang/Object;)I"),
- NATIVE_METHOD(Field, getLong, "!(Ljava/lang/Object;)J"),
- NATIVE_METHOD(Field, getShort, "!(Ljava/lang/Object;)S"),
- NATIVE_METHOD(Field, set, "!(Ljava/lang/Object;Ljava/lang/Object;)V"),
- NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;Z)V"),
- NATIVE_METHOD(Field, setByte, "!(Ljava/lang/Object;B)V"),
- NATIVE_METHOD(Field, setChar, "!(Ljava/lang/Object;C)V"),
- NATIVE_METHOD(Field, setDouble, "!(Ljava/lang/Object;D)V"),
- NATIVE_METHOD(Field, setFloat, "!(Ljava/lang/Object;F)V"),
- NATIVE_METHOD(Field, setInt, "!(Ljava/lang/Object;I)V"),
- NATIVE_METHOD(Field, setLong, "!(Ljava/lang/Object;J)V"),
- NATIVE_METHOD(Field, setShort, "!(Ljava/lang/Object;S)V"),
+ NATIVE_METHOD(Field, get, "!(Ljava/lang/Object;Z)Ljava/lang/Object;"),
+ NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;Z)Z"),
+ NATIVE_METHOD(Field, getByte, "!(Ljava/lang/Object;Z)B"),
+ NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;Z)C"),
+ NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;Z)D"),
+ NATIVE_METHOD(Field, getFloat, "!(Ljava/lang/Object;Z)F"),
+ NATIVE_METHOD(Field, getInt, "!(Ljava/lang/Object;Z)I"),
+ NATIVE_METHOD(Field, getLong, "!(Ljava/lang/Object;Z)J"),
+ NATIVE_METHOD(Field, getShort, "!(Ljava/lang/Object;Z)S"),
+ NATIVE_METHOD(Field, set, "!(Ljava/lang/Object;Ljava/lang/Object;Z)V"),
+ NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;ZZ)V"),
+ NATIVE_METHOD(Field, setByte, "!(Ljava/lang/Object;BZ)V"),
+ NATIVE_METHOD(Field, setChar, "!(Ljava/lang/Object;CZ)V"),
+ NATIVE_METHOD(Field, setDouble, "!(Ljava/lang/Object;DZ)V"),
+ NATIVE_METHOD(Field, setFloat, "!(Ljava/lang/Object;FZ)V"),
+ NATIVE_METHOD(Field, setInt, "!(Ljava/lang/Object;IZ)V"),
+ NATIVE_METHOD(Field, setLong, "!(Ljava/lang/Object;JZ)V"),
+ NATIVE_METHOD(Field, setShort, "!(Ljava/lang/Object;SZ)V"),
};
void register_java_lang_reflect_Field(JNIEnv* env) {