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 
368                     // read lists
369                     (parcel, provider) -> {
370                         TestClassLoader loader = new TestClassLoader();
371                         parcel.readArrayList(loader);
372                     },
373                     (parcel, provider) -> {
374                         TestClassLoader loader = new TestClassLoader();
375                         parcel.readArrayList(loader, Object.class);
376                     },
377                     (parcel, provider) -> {
378                         TestClassLoader loader = new TestClassLoader();
379                         parcel.readArrayList(loader, SomeParcelable.class);
380                     },
381 
382                     // read sparse arrays
383                     (parcel, provider) -> {
384                         TestClassLoader loader = new TestClassLoader();
385                         parcel.readSparseArray(loader);
386                     },
387                     (parcel, provider) -> {
388                         TestClassLoader loader = new TestClassLoader();
389                         parcel.readSparseArray(loader, Object.class);
390                     },
391                     (parcel, provider) -> {
392                         TestClassLoader loader = new TestClassLoader();
393                         parcel.readSparseArray(loader, SomeParcelable.class);
394                     },
395                     (parcel, provider) -> {
396                         TestClassLoader loader = new TestClassLoader();
397                         parcel.readSerializable(loader, Object.class);
398                     },
399 
400                     // read interface
401                     (parcel, provider) -> {
402                         TestInterface[] array;
403                         if (provider.consumeBoolean()) {
404                             int pos = parcel.dataPosition();
405                             if (pos < 0) return;
406                             array = new TestInterface[Math.min(MAX_LEN, parcel.readInt())];
407                             parcel.setDataPosition(pos);
408                         } else {
409                             array = new TestInterface[provider.consumeInt(MIN_LEN, MAX_LEN)];
410                         }
411                         parcel.readInterfaceArray(array, TestInterface::asInterface);
412                     },
413                     (parcel, provider) -> {
414                         int w = provider.consumeInt(MIN_LEN, MAX_LEN);
415                         int h = provider.consumeInt(MIN_LEN, MAX_LEN);
416                         TestInterface[][] array = new TestInterface[w][h];
417                         parcel.readFixedArray(array, TestInterface::asInterface);
418                     },
419                     (parcel, provider) -> {
420                         ArrayList<TestInterface> array = new ArrayList<TestInterface>();
421                         parcel.readInterfaceList(array, TestInterface::asInterface);
422                     },
423 
424                     // read bundle
425                     (parcel, provider) -> {
426                         TestClassLoader loader = new TestClassLoader();
427                         parcel.readBundle(loader);
428                     },
429                     (parcel, provider) -> {
430                         parcel.readBundle();
431                     },
432 
433                     // read HashMap
434                     (parcel, provider) -> {
435                         TestClassLoader loader = new TestClassLoader();
436                         parcel.readHashMap(loader);
437                     },
438                     (parcel, provider) -> {
439                         TestClassLoader loader = new TestClassLoader();
440                         parcel.readHashMap(loader, String.class, String.class);
441                     },
442                     (parcel, provider) -> {
443                         HashMap<String, String> hashMap = new HashMap<>();
444                         TestClassLoader loader = new TestClassLoader();
445                         parcel.readMap(hashMap, loader, String.class, String.class);
446                     },
447             };
448 }
449