xref: /aosp_15_r20/external/libmpeg2/fuzzer/mpeg2_dec_fuzzer.cpp (revision a97c2a1f0a796dc32bed80d3353c69c5fc07c750)
1 /******************************************************************************
2  *
3  * Copyright (C) 2019 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19  */
20 
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <algorithm>
27 #include <memory>
28 
29 #include "iv_datatypedef.h"
30 #include "iv.h"
31 #include "ivd.h"
32 #include "impeg2d.h"
33 
34 #define ALIGN2(x) ((((x) + 1) >> 1) << 1)
35 #define MAX_FRAME_WIDTH 3840
36 #define MAX_FRAME_HEIGHT 2160
37 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
38 #define ivd_api_function impeg2d_api_function
39 const IV_COLOR_FORMAT_T supportedColorFormats[] = {IV_YUV_420P, IV_YUV_420SP_UV,
40                                                    IV_YUV_420SP_VU};
41 
42 /* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
43  * decoder defaults to a supported configuration. So same set of supported
44  * architectures can be used in arm/arm64/x86 builds */
45 const IVD_ARCH_T supportedArchitectures[] = {
46     ARCH_ARM_NONEON,  ARCH_ARM_A9Q,   ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
47     ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
48 
49 enum {
50   OFFSET_COLOR_FORMAT = 6,
51   OFFSET_NUM_CORES,
52   OFFSET_ARCH,
53   /* Should be the last entry */
54   OFFSET_MAX,
55 };
56 
57 const static int kMaxNumDecodeCalls = 100;
58 const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
59 const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
60 const static int kMaxCores = 4;
61 
62 class Codec {
63  public:
64   Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
65   ~Codec();
66 
67   void createCodec();
68   void deleteCodec();
69   void resetCodec();
70   void setCores();
71   void allocFrame();
72   void freeFrame();
73   void decodeHeader(const uint8_t *data, size_t size);
74   IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
75                                    size_t *bytesConsumed);
76   void setParams(IVD_VIDEO_DECODE_MODE_T mode);
77   void setArchitecture(IVD_ARCH_T arch);
78 
79  private:
80   IV_COLOR_FORMAT_T mColorFormat;
81   size_t mNumCores;
82   iv_obj_t *mCodec;
83   ivd_out_bufdesc_t mOutBufHandle;
84   uint32_t mWidth;
85   uint32_t mHeight;
86   uint32_t mDeinterlace;
87   uint32_t mKeepThreadsActive;
88   iv_mem_rec_t *mMemRecords;
89 };
90 
Codec(IV_COLOR_FORMAT_T colorFormat,size_t numCores)91 Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores) {
92   mColorFormat = colorFormat;
93   mNumCores = numCores;
94   mCodec = nullptr;
95   mWidth = 0;
96   mHeight = 0;
97   mDeinterlace = 1;
98   mKeepThreadsActive = 1;
99   memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
100 }
101 
~Codec()102 Codec::~Codec() {}
103 
createCodec()104 void Codec::createCodec() {
105   IV_API_CALL_STATUS_T ret;
106   UWORD32 numMemRecords;
107   size_t i;
108   void *fxns = (void *)&ivd_api_function;
109 
110   iv_num_mem_rec_ip_t get_mem_ip;
111   iv_num_mem_rec_op_t get_mem_op;
112 
113   get_mem_ip.u4_size = sizeof(get_mem_ip);
114   get_mem_op.u4_size = sizeof(get_mem_op);
115   get_mem_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
116 
117   ret = ivd_api_function(NULL, (void *)&get_mem_ip, (void *)&get_mem_op);
118   if (ret != IV_SUCCESS) {
119     return;
120   }
121 
122   numMemRecords = get_mem_op.u4_num_mem_rec;
123 
124   mMemRecords = (iv_mem_rec_t *)malloc(numMemRecords * sizeof(iv_mem_rec_t));
125   if (mMemRecords == NULL) {
126     return;
127   }
128 
129   impeg2d_fill_mem_rec_ip_t fill_mem_ip;
130   impeg2d_fill_mem_rec_op_t fill_mem_op;
131 
132   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
133   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location =
134       (iv_mem_rec_t *)mMemRecords;
135   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = MAX_FRAME_WIDTH;
136   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = MAX_FRAME_HEIGHT;
137   fill_mem_ip.u4_share_disp_buf = 0;
138   fill_mem_ip.u4_deinterlace = mDeinterlace;
139   fill_mem_ip.u4_keep_threads_active = mKeepThreadsActive;
140   fill_mem_ip.e_output_format = mColorFormat;
141 
142   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
143       sizeof(impeg2d_fill_mem_rec_ip_t);
144   fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
145       sizeof(impeg2d_fill_mem_rec_op_t);
146 
147   for (i = 0; i < numMemRecords; i++)
148     mMemRecords[i].u4_size = sizeof(iv_mem_rec_t);
149 
150   ret = ivd_api_function(NULL, (void *)&fill_mem_ip, (void *)&fill_mem_op);
151 
152   if (ret != IV_SUCCESS) {
153     return;
154   }
155   numMemRecords = fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
156 
157   iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *)mMemRecords;
158 
159   for (i = 0; i < numMemRecords; i++) {
160     if (0 != posix_memalign(&ps_mem_rec->pv_base, ps_mem_rec->u4_mem_alignment,
161                             ps_mem_rec->u4_mem_size)) {
162       return;
163     }
164 
165     if (ps_mem_rec->pv_base == NULL) {
166       return;
167     }
168 
169     ps_mem_rec++;
170   }
171 
172   mCodec = (iv_obj_t *)(iv_obj_t *)mMemRecords[0].pv_base;
173   mCodec->pv_fxns = fxns;
174   mCodec->u4_size = sizeof(iv_obj_t);
175 
176   impeg2d_init_ip_t init_ip;
177   impeg2d_init_op_t init_op;
178 
179   init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
180   init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
181   init_ip.s_ivd_init_ip_t.u4_frm_max_wd = MAX_FRAME_WIDTH;
182   init_ip.s_ivd_init_ip_t.u4_frm_max_ht = MAX_FRAME_HEIGHT;
183 
184   init_ip.u4_share_disp_buf = 0;
185   init_ip.u4_deinterlace = mDeinterlace;
186   init_ip.u4_keep_threads_active = mKeepThreadsActive;
187   init_ip.s_ivd_init_ip_t.u4_num_mem_rec = numMemRecords;
188   init_ip.s_ivd_init_ip_t.e_output_format = mColorFormat;
189   init_ip.s_ivd_init_ip_t.u4_size = sizeof(impeg2d_init_ip_t);
190   init_op.s_ivd_init_op_t.u4_size = sizeof(impeg2d_init_op_t);
191 
192   ret = ivd_api_function(mCodec, (void *)&init_ip, (void *)&init_op);
193   if (ret != IV_SUCCESS) {
194     return;
195   }
196 }
197 
deleteCodec()198 void Codec::deleteCodec() {
199   IV_API_CALL_STATUS_T ret;
200   iv_retrieve_mem_rec_ip_t retrieve_ip;
201   iv_retrieve_mem_rec_op_t retrieve_op;
202   retrieve_ip.pv_mem_rec_location = (iv_mem_rec_t *)mMemRecords;
203 
204   retrieve_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
205   retrieve_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
206   retrieve_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
207 
208   ret = ivd_api_function(mCodec, (void *)&retrieve_ip, (void *)&retrieve_op);
209 
210   if (ret != IV_SUCCESS) {
211     return;
212   }
213 
214   iv_mem_rec_t *ps_mem_rec = retrieve_ip.pv_mem_rec_location;
215   for (size_t i = 0; i < retrieve_op.u4_num_mem_rec_filled; i++) {
216     free(ps_mem_rec->pv_base);
217     ps_mem_rec++;
218   }
219   free(retrieve_ip.pv_mem_rec_location);
220 }
221 
resetCodec()222 void Codec::resetCodec() {
223   ivd_ctl_reset_ip_t s_ctl_ip;
224   ivd_ctl_reset_op_t s_ctl_op;
225 
226   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
227   s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
228   s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
229   s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
230 
231   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
232 }
233 
setCores()234 void Codec::setCores() {
235   impeg2d_ctl_set_num_cores_ip_t s_ctl_ip;
236   impeg2d_ctl_set_num_cores_op_t s_ctl_op;
237 
238   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
239   s_ctl_ip.e_sub_cmd =
240       (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES;
241   s_ctl_ip.u4_num_cores = mNumCores;
242   s_ctl_ip.u4_size = sizeof(impeg2d_ctl_set_num_cores_ip_t);
243   s_ctl_op.u4_size = sizeof(impeg2d_ctl_set_num_cores_op_t);
244 
245   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
246 }
247 
setParams(IVD_VIDEO_DECODE_MODE_T mode)248 void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
249   ivd_ctl_set_config_ip_t s_ctl_ip;
250   ivd_ctl_set_config_op_t s_ctl_op;
251 
252   s_ctl_ip.u4_disp_wd = 0;
253   s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
254   s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
255   s_ctl_ip.e_vid_dec_mode = mode;
256   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
257   s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
258   s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
259   s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
260 
261   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
262 }
263 
setArchitecture(IVD_ARCH_T arch)264 void Codec::setArchitecture(IVD_ARCH_T arch) {
265   impeg2d_ctl_set_processor_ip_t s_ctl_ip;
266   impeg2d_ctl_set_processor_op_t s_ctl_op;
267 
268   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
269   s_ctl_ip.e_sub_cmd =
270       (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_PROCESSOR;
271   s_ctl_ip.u4_arch = arch;
272   s_ctl_ip.u4_soc = SOC_GENERIC;
273   s_ctl_ip.u4_size = sizeof(impeg2d_ctl_set_processor_ip_t);
274   s_ctl_op.u4_size = sizeof(impeg2d_ctl_set_processor_op_t);
275 
276   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
277 }
freeFrame()278 void Codec::freeFrame() {
279   for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
280     if (mOutBufHandle.pu1_bufs[i]) {
281       free(mOutBufHandle.pu1_bufs[i]);
282       mOutBufHandle.pu1_bufs[i] = nullptr;
283     }
284   }
285 }
286 
allocFrame()287 void Codec::allocFrame() {
288   size_t sizes[4] = {0};
289   size_t num_bufs = 0;
290 
291   freeFrame();
292 
293   memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
294 
295   switch (mColorFormat) {
296     case IV_YUV_420SP_UV:
297       [[fallthrough]];
298     case IV_YUV_420SP_VU:
299       sizes[0] = mWidth * mHeight;
300       sizes[1] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 1;
301       num_bufs = 2;
302       break;
303     case IV_YUV_422ILE:
304       sizes[0] = mWidth * mHeight * 2;
305       num_bufs = 1;
306       break;
307     case IV_RGB_565:
308       sizes[0] = mWidth * mHeight * 2;
309       num_bufs = 1;
310       break;
311     case IV_RGBA_8888:
312       sizes[0] = mWidth * mHeight * 4;
313       num_bufs = 1;
314       break;
315     case IV_YUV_420P:
316       [[fallthrough]];
317     default:
318       sizes[0] = mWidth * mHeight;
319       sizes[1] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 2;
320       sizes[2] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 2;
321       num_bufs = 3;
322       break;
323   }
324   mOutBufHandle.u4_num_bufs = num_bufs;
325   for (int i = 0; i < num_bufs; i++) {
326     mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
327     void *buf = NULL;
328     if (0 != posix_memalign(&buf, 16, sizes[i])) {
329       return;
330     }
331     mOutBufHandle.pu1_bufs[i] = (UWORD8 *)buf;
332   }
333 }
334 
decodeHeader(const uint8_t * data,size_t size)335 void Codec::decodeHeader(const uint8_t *data, size_t size) {
336   setParams(IVD_DECODE_HEADER);
337 
338   size_t numDecodeCalls = 0;
339 
340   while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
341     IV_API_CALL_STATUS_T ret;
342     ivd_video_decode_ip_t dec_ip;
343     ivd_video_decode_op_t dec_op;
344     size_t bytes_consumed;
345 
346     memset(&dec_ip, 0, sizeof(dec_ip));
347     memset(&dec_op, 0, sizeof(dec_op));
348 
349     dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
350     dec_ip.u4_ts = 0;
351     dec_ip.pv_stream_buffer = (void *)data;
352     dec_ip.u4_num_Bytes = size;
353     dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
354     dec_op.u4_size = sizeof(ivd_video_decode_op_t);
355 
356     ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
357 
358     bytes_consumed = dec_op.u4_num_bytes_consumed;
359     /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
360      * to feed next data */
361     if (!bytes_consumed) bytes_consumed = 4;
362 
363     bytes_consumed = std::min(size, bytes_consumed);
364 
365     data += bytes_consumed;
366     size -= bytes_consumed;
367     numDecodeCalls++;
368 
369     mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
370     mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
371 
372     /* Break after successful header decode */
373     if (mWidth && mHeight) {
374       break;
375     }
376   }
377   /* if width / height are invalid, set them to defaults */
378   if (!mWidth) mWidth = 1920;
379   if (!mHeight) mHeight = 1088;
380 }
381 
decodeFrame(const uint8_t * data,size_t size,size_t * bytesConsumed)382 IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
383                                         size_t *bytesConsumed) {
384   IV_API_CALL_STATUS_T ret;
385   ivd_video_decode_ip_t dec_ip;
386   ivd_video_decode_op_t dec_op;
387 
388   memset(&dec_ip, 0, sizeof(dec_ip));
389   memset(&dec_op, 0, sizeof(dec_op));
390 
391   dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
392   dec_ip.u4_ts = 0;
393   dec_ip.pv_stream_buffer = (void *)data;
394   dec_ip.u4_num_Bytes = size;
395   dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
396   dec_ip.s_out_buffer = mOutBufHandle;
397 
398   dec_op.u4_size = sizeof(ivd_video_decode_op_t);
399 
400   ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
401   if (IMPEG2D_UNSUPPORTED_DIMENSIONS == dec_op.u4_error_code) {
402     /* In case of unsupported resolution, reset codec */
403     resetCodec();
404   } else if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
405     /* In case of change in resolution, reset codec and feed the same data
406      * again */
407     resetCodec();
408     ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
409   }
410   *bytesConsumed = dec_op.u4_num_bytes_consumed;
411 
412   /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
413    * to feed next data */
414   if (!*bytesConsumed) *bytesConsumed = 4;
415 
416   if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
417       (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
418     mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
419     mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
420     allocFrame();
421   }
422 
423   return ret;
424 }
425 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)426 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
427   if (size < 1) {
428     return 0;
429   }
430   size_t colorFormatOfst = std::min((size_t)OFFSET_COLOR_FORMAT, size - 1);
431   size_t numCoresOfst = std::min((size_t)OFFSET_NUM_CORES, size - 1);
432   size_t architectureOfst = std::min((size_t)OFFSET_ARCH, size - 1);
433   size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
434   IVD_ARCH_T arch = (IVD_ARCH_T)supportedArchitectures[architectureIdx];
435   size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
436   IV_COLOR_FORMAT_T colorFormat =
437       (IV_COLOR_FORMAT_T)(supportedColorFormats[colorFormatIdx]);
438   uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
439   size_t numDecodeCalls = 0;
440   Codec *codec = new Codec(colorFormat, numCores);
441   codec->createCodec();
442   codec->setArchitecture(arch);
443   codec->setCores();
444   codec->decodeHeader(data, size);
445   codec->setParams(IVD_DECODE_FRAME);
446   codec->allocFrame();
447 
448   while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
449     IV_API_CALL_STATUS_T ret;
450     size_t bytesConsumed;
451     ret = codec->decodeFrame(data, size, &bytesConsumed);
452 
453     bytesConsumed = std::min(size, bytesConsumed);
454     data += bytesConsumed;
455     size -= bytesConsumed;
456     numDecodeCalls++;
457   }
458 
459   codec->freeFrame();
460   codec->deleteCodec();
461   delete codec;
462   return 0;
463 }
464