1 /* 2 * Copyright (C) 2022 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 package parcelfuzzer; 17 18 import android.os.Binder; 19 import android.os.IBinder; 20 import android.os.IInterface; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 27 import parcelables.EmptyParcelable; 28 import parcelables.GenericDataParcelable; 29 import parcelables.SingleDataParcelable; 30 31 public class ReadUtils { 32 public static int MAX_LEN = 1000000; 33 public static int MIN_LEN = 0; 34 35 private static class SomeParcelable implements Parcelable { 36 private final int mValue; 37 SomeParcelable(Parcel in)38 private SomeParcelable(Parcel in) { 39 this.mValue = in.readInt(); 40 } 41 42 @Override describeContents()43 public int describeContents() { 44 return 0; 45 } 46 47 @Override writeToParcel(Parcel out, int flags)48 public void writeToParcel(Parcel out, int flags) { 49 out.writeInt(mValue); 50 } 51 52 public static Parcelable.Creator<SomeParcelable> CREATOR = 53 new Parcelable.Creator<SomeParcelable>() { 54 55 @Override 56 public SomeParcelable createFromParcel(Parcel source) { 57 return new SomeParcelable(source); 58 } 59 60 @Override 61 public SomeParcelable[] newArray(int size) { 62 return new SomeParcelable[size]; 63 } 64 }; 65 } 66 67 private static class TestClassLoader extends ClassLoader { TestClassLoader()68 TestClassLoader() { 69 super(); 70 } 71 } 72 73 private static class TestInterface implements IInterface { 74 public Binder binder; 75 private static final String DESCRIPTOR = "TestInterface"; 76 TestInterface()77 TestInterface() { 78 binder = new Binder(); 79 binder.attachInterface(this, DESCRIPTOR); 80 } 81 asBinder()82 public IBinder asBinder() { 83 return binder; 84 } 85 asInterface(IBinder binder)86 public static TestInterface asInterface(IBinder binder) { 87 if (binder != null) { 88 IInterface iface = binder.queryLocalInterface(DESCRIPTOR); 89 if (iface != null && iface instanceof TestInterface) { 90 return (TestInterface) iface; 91 } 92 } 93 return null; 94 } 95 } 96 97 public static ReadOperation[] READ_OPERATIONS = 98 new ReadOperation[] { 99 (parcel, provider) -> { 100 parcel.setDataPosition(provider.consumeInt(0, Integer.MAX_VALUE)); 101 }, 102 (parcel, provider) -> { 103 parcel.setDataCapacity(provider.consumeInt()); 104 }, 105 (parcel, provider) -> { 106 parcel.setDataSize(provider.consumeInt()); 107 }, 108 (parcel, provider) -> { 109 parcel.dataSize(); 110 }, 111 (parcel, provider) -> { 112 parcel.dataPosition(); 113 }, 114 (parcel, provider) -> { 115 parcel.dataCapacity(); 116 }, 117 118 // read basic types 119 (parcel, provider) -> { 120 parcel.readByte(); 121 }, 122 (parcel, provider) -> { 123 parcel.readBoolean(); 124 }, 125 (parcel, provider) -> { 126 parcel.readInt(); 127 }, 128 (parcel, provider) -> { 129 parcel.readLong(); 130 }, 131 (parcel, provider) -> { 132 parcel.readFloat(); 133 }, 134 (parcel, provider) -> { 135 parcel.readDouble(); 136 }, 137 (parcel, provider) -> { 138 parcel.readString(); 139 }, 140 (parcel, provider) -> { 141 parcel.readString8(); 142 }, 143 (parcel, provider) -> { 144 parcel.readString16(); 145 }, 146 (parcel, provider) -> { 147 parcel.readBlob(); 148 }, 149 (parcel, provider) -> { 150 parcel.readStrongBinder(); 151 }, 152 153 // read arrays of random length 154 (parcel, provider) -> { 155 byte[] array; 156 if (provider.consumeBoolean()) { 157 int pos = parcel.dataPosition(); 158 if (pos < 0) return; 159 array = new byte[Math.min(MAX_LEN, parcel.readInt())]; 160 parcel.setDataPosition(pos); 161 } else { 162 array = new byte[provider.consumeInt(MIN_LEN, MAX_LEN)]; 163 } 164 parcel.readByteArray(array); 165 }, 166 (parcel, provider) -> { 167 char[] array; 168 if (provider.consumeBoolean()) { 169 int pos = parcel.dataPosition(); 170 if (pos < 0) return; 171 array = new char[Math.min(MAX_LEN, parcel.readInt())]; 172 parcel.setDataPosition(pos); 173 } else { 174 array = new char[provider.consumeInt(MIN_LEN, MAX_LEN)]; 175 } 176 parcel.readCharArray(array); 177 }, 178 (parcel, provider) -> { 179 int[] array; 180 if (provider.consumeBoolean()) { 181 int pos = parcel.dataPosition(); 182 if (pos < 0) return; 183 array = new int[Math.min(MAX_LEN, parcel.readInt())]; 184 parcel.setDataPosition(pos); 185 } else { 186 array = new int[provider.consumeInt(MIN_LEN, MAX_LEN)]; 187 } 188 parcel.readIntArray(array); 189 }, 190 (parcel, provider) -> { 191 double[] array; 192 if (provider.consumeBoolean()) { 193 int pos = parcel.dataPosition(); 194 if (pos < 0) return; 195 array = new double[Math.min(MAX_LEN, parcel.readInt())]; 196 parcel.setDataPosition(pos); 197 } else { 198 array = new double[provider.consumeInt(MIN_LEN, MAX_LEN)]; 199 } 200 parcel.readDoubleArray(array); 201 }, 202 (parcel, provider) -> { 203 float[] array; 204 if (provider.consumeBoolean()) { 205 int pos = parcel.dataPosition(); 206 if (pos < 0) return; 207 array = new float[Math.min(MAX_LEN, parcel.readInt())]; 208 parcel.setDataPosition(pos); 209 } else { 210 array = new float[provider.consumeInt(MIN_LEN, MAX_LEN)]; 211 } 212 parcel.readFloatArray(array); 213 }, 214 (parcel, provider) -> { 215 boolean[] array; 216 if (provider.consumeBoolean()) { 217 int pos = parcel.dataPosition(); 218 if (pos < 0) return; 219 array = new boolean[Math.min(MAX_LEN, parcel.readInt())]; 220 parcel.setDataPosition(pos); 221 } else { 222 array = new boolean[provider.consumeInt(MIN_LEN, MAX_LEN)]; 223 } 224 parcel.readBooleanArray(array); 225 }, 226 (parcel, provider) -> { 227 long[] array; 228 if (provider.consumeBoolean()) { 229 int pos = parcel.dataPosition(); 230 if (pos < 0) return; 231 array = new long[Math.min(MAX_LEN, parcel.readInt())]; 232 parcel.setDataPosition(pos); 233 } else { 234 array = new long[provider.consumeInt(MIN_LEN, MAX_LEN)]; 235 } 236 parcel.readLongArray(array); 237 }, 238 (parcel, provider) -> { 239 IBinder[] array; 240 if (provider.consumeBoolean()) { 241 int pos = parcel.dataPosition(); 242 if (pos < 0) return; 243 array = new IBinder[Math.min(MAX_LEN, parcel.readInt())]; 244 parcel.setDataPosition(pos); 245 } else { 246 array = new IBinder[provider.consumeInt(MIN_LEN, MAX_LEN)]; 247 } 248 parcel.readBinderArray(array); 249 }, 250 (parcel, provider) -> { 251 ArrayList<IBinder> arrayList = new ArrayList<IBinder>(); 252 parcel.readBinderList(arrayList); 253 }, 254 255 // unmarshall from random parcel data and random bytes 256 (parcel, provider) -> { 257 byte[] data = parcel.marshall(); 258 Parcel p = Parcel.obtain(); 259 p.unmarshall(data, provider.consumeInt(), provider.consumeInt()); 260 p.recycle(); 261 }, 262 (parcel, provider) -> { 263 byte[] data = provider.consumeRemainingAsBytes(); 264 Parcel p = Parcel.obtain(); 265 p.unmarshall(data, provider.consumeInt(), provider.consumeInt()); 266 p.recycle(); 267 }, 268 (parcel, provider) -> { 269 parcel.hasFileDescriptors(provider.consumeInt(), provider.consumeInt()); 270 }, 271 272 // read AIDL generated parcelables 273 (parcel, provider) -> { 274 TestClassLoader loader = new TestClassLoader(); 275 parcel.readParcelable(loader, SingleDataParcelable.class); 276 }, 277 (parcel, provider) -> { 278 TestClassLoader loader = new TestClassLoader(); 279 parcel.readParcelableArray(loader, SingleDataParcelable.class); 280 }, 281 (parcel, provider) -> { 282 SingleDataParcelable[] array; 283 if (provider.consumeBoolean()) { 284 int pos = parcel.dataPosition(); 285 if (pos < 0) return; 286 array = new SingleDataParcelable[Math.min(MAX_LEN, parcel.readInt())]; 287 parcel.setDataPosition(pos); 288 } else { 289 array = new SingleDataParcelable[provider.consumeInt(MIN_LEN, MAX_LEN)]; 290 } 291 parcel.readTypedArray(array, SingleDataParcelable.CREATOR); 292 }, 293 (parcel, provider) -> { 294 TestClassLoader loader = new TestClassLoader(); 295 parcel.readParcelable(loader, EmptyParcelable.class); 296 }, 297 (parcel, provider) -> { 298 TestClassLoader loader = new TestClassLoader(); 299 parcel.readParcelableArray(loader, EmptyParcelable.class); 300 }, 301 (parcel, provider) -> { 302 EmptyParcelable[] array; 303 if (provider.consumeBoolean()) { 304 int pos = parcel.dataPosition(); 305 if (pos < 0) return; 306 array = new EmptyParcelable[Math.min(MAX_LEN, parcel.readInt())]; 307 parcel.setDataPosition(pos); 308 } else { 309 array = new EmptyParcelable[provider.consumeInt(MIN_LEN, MAX_LEN)]; 310 } 311 parcel.readTypedArray(array, EmptyParcelable.CREATOR); 312 }, 313 (parcel, provider) -> { 314 TestClassLoader loader = new TestClassLoader(); 315 parcel.readParcelable(loader, GenericDataParcelable.class); 316 }, 317 (parcel, provider) -> { 318 TestClassLoader loader = new TestClassLoader(); 319 parcel.readParcelableArray(loader, GenericDataParcelable.class); 320 }, 321 (parcel, provider) -> { 322 GenericDataParcelable[] array; 323 if (provider.consumeBoolean()) { 324 int pos = parcel.dataPosition(); 325 if (pos < 0) return; 326 array = new GenericDataParcelable[Math.min(MAX_LEN, parcel.readInt())]; 327 parcel.setDataPosition(pos); 328 } else { 329 int len = provider.consumeInt(MIN_LEN, MAX_LEN); 330 array = new GenericDataParcelable[len]; 331 } 332 parcel.readTypedArray(array, GenericDataParcelable.CREATOR); 333 }, 334 335 // read parcelables 336 (parcel, provider) -> { 337 TestClassLoader loader = new TestClassLoader(); 338 parcel.readParcelable(loader, SomeParcelable.class); 339 }, 340 (parcel, provider) -> { 341 TestClassLoader loader = new TestClassLoader(); 342 parcel.readParcelableArray(loader, SomeParcelable.class); 343 }, 344 (parcel, provider) -> { 345 SomeParcelable[] array; 346 if (provider.consumeBoolean()) { 347 int pos = parcel.dataPosition(); 348 if (pos < 0) return; 349 array = new SomeParcelable[Math.min(MAX_LEN, parcel.readInt())]; 350 parcel.setDataPosition(pos); 351 } else { 352 array = new SomeParcelable[provider.consumeInt(MIN_LEN, MAX_LEN)]; 353 } 354 parcel.readTypedArray(array, SomeParcelable.CREATOR); 355 }, 356 (parcel, provider) -> { 357 TestClassLoader loader = new TestClassLoader(); 358 parcel.readParcelableArray(loader); 359 }, 360 (parcel, provider) -> { 361 parcel.hasFileDescriptors(provider.consumeInt(), provider.consumeInt()); 362 }, 363 (parcel, provider) -> { 364 TestClassLoader loader = new TestClassLoader(); 365 parcel.readParcelableArray(loader); 366 }, 367 (parcel, provider) -> { 368 parcel.readParcelable(null); 369 }, 370 (parcel, provider) -> { 371 parcel.readParcelableArray(null); 372 }, 373 374 // read lists 375 (parcel, provider) -> { 376 TestClassLoader loader = new TestClassLoader(); 377 parcel.readArrayList(loader); 378 }, 379 (parcel, provider) -> { 380 TestClassLoader loader = new TestClassLoader(); 381 parcel.readArrayList(loader, Object.class); 382 }, 383 (parcel, provider) -> { 384 TestClassLoader loader = new TestClassLoader(); 385 parcel.readArrayList(loader, SomeParcelable.class); 386 }, 387 388 // read sparse arrays 389 (parcel, provider) -> { 390 TestClassLoader loader = new TestClassLoader(); 391 parcel.readSparseArray(loader); 392 }, 393 (parcel, provider) -> { 394 TestClassLoader loader = new TestClassLoader(); 395 parcel.readSparseArray(loader, Object.class); 396 }, 397 (parcel, provider) -> { 398 TestClassLoader loader = new TestClassLoader(); 399 parcel.readSparseArray(loader, SomeParcelable.class); 400 }, 401 (parcel, provider) -> { 402 TestClassLoader loader = new TestClassLoader(); 403 parcel.readSerializable(loader, Object.class); 404 }, 405 406 // read interface 407 (parcel, provider) -> { 408 TestInterface[] array; 409 if (provider.consumeBoolean()) { 410 int pos = parcel.dataPosition(); 411 if (pos < 0) return; 412 array = new TestInterface[Math.min(MAX_LEN, parcel.readInt())]; 413 parcel.setDataPosition(pos); 414 } else { 415 array = new TestInterface[provider.consumeInt(MIN_LEN, MAX_LEN)]; 416 } 417 parcel.readInterfaceArray(array, TestInterface::asInterface); 418 }, 419 (parcel, provider) -> { 420 int w = provider.consumeInt(MIN_LEN, MAX_LEN); 421 int h = provider.consumeInt(MIN_LEN, MAX_LEN); 422 TestInterface[][] array = new TestInterface[w][h]; 423 parcel.readFixedArray(array, TestInterface::asInterface); 424 }, 425 (parcel, provider) -> { 426 ArrayList<TestInterface> array = new ArrayList<TestInterface>(); 427 parcel.readInterfaceList(array, TestInterface::asInterface); 428 }, 429 430 // read bundle 431 (parcel, provider) -> { 432 TestClassLoader loader = new TestClassLoader(); 433 parcel.readBundle(loader); 434 }, 435 (parcel, provider) -> { 436 parcel.readBundle(); 437 }, 438 439 // read HashMap 440 (parcel, provider) -> { 441 TestClassLoader loader = new TestClassLoader(); 442 parcel.readHashMap(loader); 443 }, 444 (parcel, provider) -> { 445 TestClassLoader loader = new TestClassLoader(); 446 parcel.readHashMap(loader, String.class, String.class); 447 }, 448 (parcel, provider) -> { 449 HashMap<String, String> hashMap = new HashMap<>(); 450 TestClassLoader loader = new TestClassLoader(); 451 parcel.readMap(hashMap, loader, String.class, String.class); 452 }, 453 }; 454 } 455