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