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 
27 #include <algorithm>
28 #include <memory>
29 
30 #include "ih264_typedefs.h"
31 #include "ih264d.h"
32 #include "iv.h"
33 #include "ivd.h"
34 
35 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
36 #define ivd_api_function ih264d_api_function
37 const IV_COLOR_FORMAT_T supportedColorFormats[] = {
38     IV_YUV_420P,   IV_YUV_420SP_UV, IV_YUV_420SP_VU,
39     IV_YUV_422ILE, IV_RGB_565,      IV_RGBA_8888};
40 
41 /* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
42  * decoder defaults to a supported configuration. So same set of supported
43  * architectures can be used in arm/arm64/x86 builds */
44 const IVD_ARCH_T supportedArchitectures[] = {
45     ARCH_ARM_NONEON,  ARCH_ARM_A9Q,   ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
46     ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
47 
48 enum {
49   OFFSET_COLOR_FORMAT = 6,
50   OFFSET_NUM_CORES,
51   OFFSET_ARCH,
52   /* Should be the last entry */
53   OFFSET_MAX,
54 };
55 
56 const static int kMaxNumDecodeCalls = 100;
57 const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
58 const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
59 const static int kMaxCores = 4;
iv_aligned_malloc(void * ctxt,WORD32 alignment,WORD32 size)60 void *iv_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
61   void *buf = NULL;
62   (void)ctxt;
63   if (0 != posix_memalign(&buf, alignment, size)) {
64       return NULL;
65   }
66   return buf;
67 }
68 
iv_aligned_free(void * ctxt,void * buf)69 void iv_aligned_free(void *ctxt, void *buf) {
70   (void)ctxt;
71   free(buf);
72 }
73 
74 class Codec {
75  public:
76   Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
77   ~Codec();
78 
79   void createCodec();
80   void deleteCodec();
81   void resetCodec();
82   void setCores();
83   void allocFrame();
84   void freeFrame();
85   void decodeHeader(const uint8_t *data, size_t size);
86   IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
87                                    size_t *bytesConsumed);
88   void setParams(IVD_VIDEO_DECODE_MODE_T mode);
89   void setArchitecture(IVD_ARCH_T arch);
90 
91  private:
92   IV_COLOR_FORMAT_T mColorFormat;
93   size_t mNumCores;
94   iv_obj_t *mCodec;
95   ivd_out_bufdesc_t mOutBufHandle;
96   uint32_t mWidth;
97   uint32_t mHeight;
98 };
99 
Codec(IV_COLOR_FORMAT_T colorFormat,size_t numCores)100 Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores) {
101   mColorFormat = colorFormat;
102   mNumCores = numCores;
103   mCodec = nullptr;
104   mWidth = 0;
105   mHeight = 0;
106 
107   memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
108 }
~Codec()109 Codec::~Codec() {}
createCodec()110 void Codec::createCodec() {
111   IV_API_CALL_STATUS_T ret;
112   ih264d_create_ip_t create_ip;
113   ih264d_create_op_t create_op;
114   void *fxns = (void *)&ivd_api_function;
115 
116   create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
117   create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
118   create_ip.s_ivd_create_ip_t.e_output_format = mColorFormat;
119   create_ip.s_ivd_create_ip_t.pf_aligned_alloc = iv_aligned_malloc;
120   create_ip.s_ivd_create_ip_t.pf_aligned_free = iv_aligned_free;
121   create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
122   create_ip.s_ivd_create_ip_t.u4_size = sizeof(ih264d_create_ip_t);
123   create_op.s_ivd_create_op_t.u4_size = sizeof(ih264d_create_op_t);
124 
125   ret = ivd_api_function(NULL, (void *)&create_ip, (void *)&create_op);
126   if (ret != IV_SUCCESS) {
127     return;
128   }
129   mCodec = (iv_obj_t *)create_op.s_ivd_create_op_t.pv_handle;
130   mCodec->pv_fxns = fxns;
131   mCodec->u4_size = sizeof(iv_obj_t);
132 }
133 
deleteCodec()134 void Codec::deleteCodec() {
135   ivd_delete_ip_t delete_ip;
136   ivd_delete_op_t delete_op;
137 
138   delete_ip.e_cmd = IVD_CMD_DELETE;
139   delete_ip.u4_size = sizeof(ivd_delete_ip_t);
140   delete_op.u4_size = sizeof(ivd_delete_op_t);
141 
142   ivd_api_function(mCodec, (void *)&delete_ip, (void *)&delete_op);
143 }
resetCodec()144 void Codec::resetCodec() {
145   ivd_ctl_reset_ip_t s_ctl_ip;
146   ivd_ctl_reset_op_t s_ctl_op;
147 
148   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
149   s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
150   s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
151   s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
152 
153   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
154 }
155 
setCores()156 void Codec::setCores() {
157   ih264d_ctl_set_num_cores_ip_t s_ctl_ip;
158   ih264d_ctl_set_num_cores_op_t s_ctl_op;
159 
160   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
161   s_ctl_ip.e_sub_cmd =
162       (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES;
163   s_ctl_ip.u4_num_cores = mNumCores;
164   s_ctl_ip.u4_size = sizeof(ih264d_ctl_set_num_cores_ip_t);
165   s_ctl_op.u4_size = sizeof(ih264d_ctl_set_num_cores_op_t);
166 
167   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
168 }
169 
setParams(IVD_VIDEO_DECODE_MODE_T mode)170 void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
171   ivd_ctl_set_config_ip_t s_ctl_ip;
172   ivd_ctl_set_config_op_t s_ctl_op;
173 
174   s_ctl_ip.u4_disp_wd = 0;
175   s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
176   s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
177   s_ctl_ip.e_vid_dec_mode = mode;
178   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
179   s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
180   s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
181   s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
182 
183   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
184 }
185 
setArchitecture(IVD_ARCH_T arch)186 void Codec::setArchitecture(IVD_ARCH_T arch) {
187   ih264d_ctl_set_processor_ip_t s_ctl_ip;
188   ih264d_ctl_set_processor_op_t s_ctl_op;
189 
190   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
191   s_ctl_ip.e_sub_cmd =
192       (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_PROCESSOR;
193   s_ctl_ip.u4_arch = arch;
194   s_ctl_ip.u4_soc = SOC_GENERIC;
195   s_ctl_ip.u4_size = sizeof(ih264d_ctl_set_processor_ip_t);
196   s_ctl_op.u4_size = sizeof(ih264d_ctl_set_processor_op_t);
197 
198   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
199 }
freeFrame()200 void Codec::freeFrame() {
201   for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
202     if (mOutBufHandle.pu1_bufs[i]) {
203       free(mOutBufHandle.pu1_bufs[i]);
204       mOutBufHandle.pu1_bufs[i] = nullptr;
205     }
206   }
207 }
allocFrame()208 void Codec::allocFrame() {
209   size_t sizes[4] = {0};
210   size_t num_bufs = 0;
211 
212   freeFrame();
213 
214   memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
215 
216   switch (mColorFormat) {
217     case IV_YUV_420SP_UV:
218       [[fallthrough]];
219     case IV_YUV_420SP_VU:
220       sizes[0] = mWidth * mHeight;
221       sizes[1] = mWidth * mHeight >> 1;
222       num_bufs = 2;
223       break;
224     case IV_YUV_422ILE:
225       sizes[0] = mWidth * mHeight * 2;
226       num_bufs = 1;
227       break;
228     case IV_RGB_565:
229       sizes[0] = mWidth * mHeight * 2;
230       num_bufs = 1;
231       break;
232     case IV_RGBA_8888:
233       sizes[0] = mWidth * mHeight * 4;
234       num_bufs = 1;
235       break;
236     case IV_YUV_420P:
237       [[fallthrough]];
238     default:
239       sizes[0] = mWidth * mHeight;
240       sizes[1] = mWidth * mHeight >> 2;
241       sizes[2] = mWidth * mHeight >> 2;
242       num_bufs = 3;
243       break;
244   }
245   mOutBufHandle.u4_num_bufs = num_bufs;
246   for (int i = 0; i < num_bufs; i++) {
247     mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
248     mOutBufHandle.pu1_bufs[i] = (UWORD8 *)iv_aligned_malloc(NULL, 16, sizes[i]);
249   }
250 }
decodeHeader(const uint8_t * data,size_t size)251 void Codec::decodeHeader(const uint8_t *data, size_t size) {
252   setParams(IVD_DECODE_HEADER);
253 
254   while (size > 0) {
255     IV_API_CALL_STATUS_T ret;
256     ivd_video_decode_ip_t dec_ip;
257     ivd_video_decode_op_t dec_op;
258     size_t bytes_consumed;
259 
260     memset(&dec_ip, 0, sizeof(dec_ip));
261     memset(&dec_op, 0, sizeof(dec_op));
262 
263     dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
264     dec_ip.u4_ts = 0;
265     dec_ip.pv_stream_buffer = (void *)data;
266     dec_ip.u4_num_Bytes = size;
267     dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
268     dec_op.u4_size = sizeof(ivd_video_decode_op_t);
269 
270     ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
271 
272     bytes_consumed = dec_op.u4_num_bytes_consumed;
273     /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
274      * to feed next data */
275     if (!bytes_consumed) bytes_consumed = 4;
276 
277     bytes_consumed = std::min(size, bytes_consumed);
278 
279     data += bytes_consumed;
280     size -= bytes_consumed;
281 
282     mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
283     mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
284 
285     /* Break after successful header decode */
286     if (mWidth && mHeight) {
287       break;
288     }
289   }
290   /* if width / height are invalid, set them to defaults */
291   if (!mWidth) mWidth = 1920;
292   if (!mHeight) mHeight = 1088;
293 }
294 
decodeFrame(const uint8_t * data,size_t size,size_t * bytesConsumed)295 IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
296                                         size_t *bytesConsumed) {
297   IV_API_CALL_STATUS_T ret;
298   ivd_video_decode_ip_t dec_ip;
299   ivd_video_decode_op_t dec_op;
300 
301   memset(&dec_ip, 0, sizeof(dec_ip));
302   memset(&dec_op, 0, sizeof(dec_op));
303 
304   dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
305   dec_ip.u4_ts = 0;
306   dec_ip.pv_stream_buffer = (void *)data;
307   dec_ip.u4_num_Bytes = size;
308   dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
309   dec_ip.s_out_buffer = mOutBufHandle;
310 
311   dec_op.u4_size = sizeof(ivd_video_decode_op_t);
312 
313   ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
314 
315   /* In case of change in resolution, reset codec and feed the same data again
316    */
317   if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
318     resetCodec();
319     ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
320   }
321   *bytesConsumed = dec_op.u4_num_bytes_consumed;
322 
323   /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
324    * to feed next data */
325   if (!*bytesConsumed) *bytesConsumed = 4;
326 
327   if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
328       (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
329     mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
330     mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
331     allocFrame();
332   }
333 
334   return ret;
335 }
336 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)337 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
338   if (size < 1) {
339     return 0;
340   }
341   size_t colorFormatOfst = std::min((size_t)OFFSET_COLOR_FORMAT, size - 1);
342   size_t numCoresOfst = std::min((size_t)OFFSET_NUM_CORES, size - 1);
343   size_t architectureOfst = std::min((size_t)OFFSET_ARCH, size - 1);
344   size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
345   IVD_ARCH_T arch = (IVD_ARCH_T)supportedArchitectures[architectureIdx];
346   size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
347   IV_COLOR_FORMAT_T colorFormat =
348       (IV_COLOR_FORMAT_T)(supportedColorFormats[colorFormatIdx]);
349   uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
350   size_t numDecodeCalls = 0;
351   Codec *codec = new Codec(colorFormat, numCores);
352   codec->createCodec();
353   codec->setArchitecture(arch);
354   codec->setCores();
355   codec->decodeHeader(data, size);
356   codec->setParams(IVD_DECODE_FRAME);
357   codec->allocFrame();
358 
359   while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
360     IV_API_CALL_STATUS_T ret;
361     size_t bytesConsumed;
362     ret = codec->decodeFrame(data, size, &bytesConsumed);
363 
364     bytesConsumed = std::min(size, bytesConsumed);
365     data += bytesConsumed;
366     size -= bytesConsumed;
367     numDecodeCalls++;
368   }
369 
370   codec->freeFrame();
371   codec->deleteCodec();
372   delete codec;
373   return 0;
374 }
375