1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import art.Redefinition; 18 import java.util.Base64; 19 20 public class DexCacheSmash { 21 static class Transform { foo()22 public void foo() {} bar()23 public void bar() {} getId()24 public String getId() { 25 return "TRANSFORM_INITIAL"; 26 } 27 } 28 29 static class Transform2 { getId()30 public String getId() { 31 return "TRANSFORM2_INITIAL"; 32 } 33 } 34 35 /** 36 * A base64 encoding of the dex/class file of the Transform class above. 37 */ 38 static final byte[] TRANSFORM_INITIAL_CLASS_FILE_BYTES = Base64.getDecoder().decode( 39 "yv66vgAAADQAFwoABAAPCAAQBwASBwAVAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1i" + 40 "ZXJUYWJsZQEAA2ZvbwEAA2JhcgEABWdldElkAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3Vy" + 41 "Y2VGaWxlAQASRGV4Q2FjaGVTbWFzaC5qYXZhDAAFAAYBABFUUkFOU0ZPUk1fSU5JVElBTAcAFgEA" + 42 "F0RleENhY2hlU21hc2gkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2" + 43 "YS9sYW5nL09iamVjdAEADURleENhY2hlU21hc2gAIAADAAQAAAAAAAQAAAAFAAYAAQAHAAAAHQAB" + 44 "AAEAAAAFKrcAAbEAAAABAAgAAAAGAAEAAAATAAEACQAGAAEABwAAABkAAAABAAAAAbEAAAABAAgA" + 45 "AAAGAAEAAAAUAAEACgAGAAEABwAAABkAAAABAAAAAbEAAAABAAgAAAAGAAEAAAAVAAEACwAMAAEA" + 46 "BwAAABsAAQABAAAAAxICsAAAAAEACAAAAAYAAQAAABcAAgANAAAAAgAOABQAAAAKAAEAAwARABMA" + 47 "CA=="); 48 static final byte[] TRANSFORM_INITIAL_DEX_FILE_BYTES = Base64.getDecoder().decode( 49 "ZGV4CjAzNQDhg9CfghG1SRlLClguRuFYsqihr4F7NsGQAwAAcAAAAHhWNBIAAAAAAAAAAOQCAAAS" + 50 "AAAAcAAAAAcAAAC4AAAAAgAAANQAAAAAAAAAAAAAAAUAAADsAAAAAQAAABQBAABcAgAANAEAAKgB" + 51 "AACwAQAAxAEAAMcBAADiAQAA8wEAABcCAAA3AgAASwIAAF8CAAByAgAAfQIAAIACAACNAgAAkgIA" + 52 "AJcCAACeAgAApAIAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAsAAAACAAAABQAAAAAAAAALAAAA" + 53 "BgAAAAAAAAAAAAEAAAAAAAAAAQANAAAAAAABAA4AAAAAAAAADwAAAAQAAQAAAAAAAAAAAAAAAAAE" + 54 "AAAAAAAAAAEAAACYAQAAzgIAAAAAAAACAAAAvwIAAMUCAAABAAEAAQAAAKsCAAAEAAAAcBAEAAAA" + 55 "DgABAAEAAAAAALACAAABAAAADgAAAAEAAQAAAAAAtQIAAAEAAAAOAAAAAgABAAAAAAC6AgAAAwAA" + 56 "ABoACQARAAAANAEAAAAAAAAAAAAAAAAAAAY8aW5pdD4AEkRleENhY2hlU21hc2guamF2YQABTAAZ" + 57 "TERleENhY2hlU21hc2gkVHJhbnNmb3JtOwAPTERleENhY2hlU21hc2g7ACJMZGFsdmlrL2Fubm90" + 58 "YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsAEkxq" + 59 "YXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABFUUkFOU0ZPUk1fSU5JVElBTAAJ" + 60 "VHJhbnNmb3JtAAFWAAthY2Nlc3NGbGFncwADYmFyAANmb28ABWdldElkAARuYW1lAAV2YWx1ZQAT" + 61 "AAcOABUABw4AFAAHDgAXAAcOAAICAREYAQIDAgwECBAXCgAAAQMAgIAEwAIBAdgCAQHsAgEBgAMO" + 62 "AAAAAAAAAAEAAAAAAAAAAQAAABIAAABwAAAAAgAAAAcAAAC4AAAAAwAAAAIAAADUAAAABQAAAAUA" + 63 "AADsAAAABgAAAAEAAAAUAQAAAxAAAAEAAAA0AQAAASAAAAQAAABAAQAABiAAAAEAAACYAQAAAiAA" + 64 "ABIAAACoAQAAAyAAAAQAAACrAgAABCAAAAIAAAC/AgAAACAAAAEAAADOAgAAABAAAAEAAADkAgAA"); 65 static final Redefinition.CommonClassDefinition TRANSFORM_INITIAL = 66 new Redefinition.CommonClassDefinition(Transform.class, 67 TRANSFORM_INITIAL_CLASS_FILE_BYTES, TRANSFORM_INITIAL_DEX_FILE_BYTES); 68 69 /** 70 * A base64 encoding of the following (invalid) class. 71 * 72 * .class LDexCacheSmash$Transform2; 73 * .super Ljava/lang/Object; 74 * .source "DexCacheSmash.java" 75 * 76 * # annotations 77 * .annotation system Ldalvik/annotation/EnclosingClass; 78 * value = LDexCacheSmash; 79 * .end annotation 80 * 81 * .annotation system Ldalvik/annotation/InnerClass; 82 * accessFlags = 0x8 83 * name = "Transform2" 84 * .end annotation 85 * 86 * 87 * # direct methods 88 * .method constructor <init>()V 89 * .registers 1 90 * 91 * .prologue 92 * .line 26 93 * invoke-direct {p0}, Ljava/lang/Object;-><init>()V 94 * 95 * return-void 96 * .end method 97 * 98 * 99 * # virtual methods 100 * .method public getId()Ljava/lang/String; 101 * .registers 2 102 * 103 * .prologue 104 * .line 28 105 * # NB Fails verification due to this function not returning a String. 106 * return-void 107 * .end method 108 */ 109 static final byte[] TRANSFORM2_INVALID_CLASS_FILE_BYTES = Base64.getDecoder().decode( 110 "yv66vgAAADQAEwcAEgcAEQEABjxpbml0PgEAAygpVgEABENvZGUKAAIAEAEAD0xpbmVOdW1iZXJU" + 111 "YWJsZQEABWdldElkAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQASRGV4Q2Fj" + 112 "aGVTbWFzaC5qYXZhAQAMSW5uZXJDbGFzc2VzBwAPAQAKVHJhbnNmb3JtMgEADURleENhY2hlU21h" + 113 "c2gMAAMABAEAEGphdmEvbGFuZy9PYmplY3QBABhEZXhDYWNoZVNtYXNoJFRyYW5zZm9ybTIAIAAB" + 114 "AAIAAAAAAAIAAAADAAQAAQAFAAAAHQABAAEAAAAFKrcABrEAAAABAAcAAAAGAAEAAAAaAAEACAAJ" + 115 "AAEABQAAABkAAQABAAAAAbEAAAABAAcAAAAGAAEAAAAcAAIACgAAAAIACwAMAAAACgABAAEADQAO" + 116 "AAg="); 117 static final byte[] TRANSFORM2_INVALID_DEX_FILE_BYTES = Base64.getDecoder().decode( 118 "ZGV4CjAzNQCFcegr6Ns+I7iEF4uLRkUX4yGrLhP6soEgAwAAcAAAAHhWNBIAAAAAAAAAAHQCAAAP" + 119 "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAAAAAAAAAAAAAMAAADgAAAAAQAAAPgAAAAIAgAAGAEAABgB" + 120 "AAAgAQAANAEAADcBAABTAQAAZAEAAIgBAACoAQAAvAEAANABAADcAQAA3wEAAOwBAADzAQAA+QEA" + 121 "AAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAoAAAACAAAABQAAAAAAAAAKAAAABgAAAAAAAAAAAAEA" + 122 "AAAAAAAAAAAMAAAABAABAAAAAAAAAAAAAAAAAAQAAAAAAAAAAQAAACACAABmAgAAAAAAAAY8aW5p" + 123 "dD4AEkRleENhY2hlU21hc2guamF2YQABTAAaTERleENhY2hlU21hc2gkVHJhbnNmb3JtMjsAD0xE" + 124 "ZXhDYWNoZVNtYXNoOwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZp" + 125 "ay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcv" + 126 "U3RyaW5nOwAKVHJhbnNmb3JtMgABVgALYWNjZXNzRmxhZ3MABWdldElkAARuYW1lAAV2YWx1ZQAC" + 127 "AwILBAgNFwkCAgEOGAEAAAAAAAIAAAAJAgAAAAIAABQCAAAAAAAAAAAAAAAAAAAaAAcOABwABw4A" + 128 "AAABAAEAAQAAADACAAAEAAAAcBACAAAADgACAAEAAAAAADUCAAABAAAADgAAAAEBAICABLwEAQHU" + 129 "BA4AAAAAAAAAAQAAAAAAAAABAAAADwAAAHAAAAACAAAABwAAAKwAAAADAAAAAgAAAMgAAAAFAAAA" + 130 "AwAAAOAAAAAGAAAAAQAAAPgAAAACIAAADwAAABgBAAAEIAAAAgAAAAACAAADEAAAAgAAABACAAAG" + 131 "IAAAAQAAACACAAADIAAAAgAAADACAAABIAAAAgAAADwCAAAAIAAAAQAAAGYCAAAAEAAAAQAAAHQC" + 132 "AAA="); 133 static final Redefinition.CommonClassDefinition TRANSFORM2_INVALID = 134 new Redefinition.CommonClassDefinition(Transform2.class, 135 TRANSFORM2_INVALID_CLASS_FILE_BYTES, TRANSFORM2_INVALID_DEX_FILE_BYTES); 136 run()137 public static void run() throws Exception { 138 try { 139 Redefinition.doMultiClassRedefinition(TRANSFORM2_INVALID); 140 } catch (Exception e) { 141 if (!e.getMessage().contains("JVMTI_ERROR_FAILS_VERIFICATION")) { 142 throw new Error( 143 "Unexpected error: Expected failure due to JVMTI_ERROR_FAILS_VERIFICATION", 144 e); 145 } 146 } 147 // Doing this redefinition after a redefinition that failed due to FAILS_VERIFICATION could 148 // cause a use-after-free of the Transform2's DexCache by the redefinition code if it 149 // happens that the native pointer of the art::DexFile created for the Transform 150 // redefinition aliases the one created for Transform2's failed redefinition. 151 // 152 // Due to the order of checks performed by the redefinition code FAILS_VERIFICATION is the 153 // only failure mode that can cause Use-after-frees in this way. 154 // 155 // This should never throw any exceptions (except perhaps OOME in very strange 156 // circumstances). 157 Redefinition.doMultiClassRedefinition(TRANSFORM_INITIAL); 158 } 159 } 160