1 /*
2  * Copyright (C) 2020 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 
17 #include <fuzzer/FuzzedDataProvider.h>
18 
19 #include "../g722_enc_dec.h"
20 
21 namespace {
22 
get_rate_from_fdp(FuzzedDataProvider * fdp)23 uint32_t get_rate_from_fdp(FuzzedDataProvider* fdp) {
24   uint32_t rate = fdp->ConsumeIntegralInRange<uint32_t>(
25       0, 3);  // Currently 3 different bit rates are available in G.722 codec
26   switch (rate) {
27     case 0:
28       return 48000;
29     case 1:
30       return 56000;
31     default:
32       return 64000;
33   }
34 }
35 
fuzz_encode(FuzzedDataProvider * fdp)36 void fuzz_encode(FuzzedDataProvider* fdp) {
37   uint32_t rate = get_rate_from_fdp(fdp);
38   std::vector<uint8_t> buff = fdp->ConsumeRemainingBytes<uint8_t>();
39 
40   int num_samples =
41       buff.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/);
42 
43   // The G.722 codec accept only even number of samples for encoding
44   if (num_samples % 2 != 0) {
45     num_samples--;
46   }
47 
48   // Making channel data from buffer
49   std::vector<uint16_t> channel_data;
50 
51   for (int i = 0; i < num_samples; i++) {
52     const uint8_t* sample = buff.data() + i * 2;
53     int16_t left = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
54 
55     sample += 2;
56     int16_t right = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
57 
58     uint16_t mono_data = (int16_t)(((uint32_t)left + (uint32_t)right) >> 1);
59     channel_data.push_back(mono_data);
60   }
61 
62   // Encoder Initialization
63   g722_encode_state_t* encoder_state = nullptr;
64   encoder_state = g722_encode_init(nullptr, rate, G722_PACKED);
65 
66   // Encode
67   std::vector<uint8_t> encoded_data;
68   // Magic number is used in api, It should basically fit the number generated
69   // by this formula : num_channels * sample_rate * data_interval_ms
70   // * (bit_rate / 8)) / 1000 as mentioned in hearing_aid.cc And if we fit all
71   // the values in the above formula, the max value we can get is 1920. And I
72   // used "size" of the input that libfuzzer generates as the initial
73   // parameter to resize
74   encoded_data.resize(buff.size());
75   int encoded_size =
76       g722_encode(encoder_state, encoded_data.data(),
77                   (const int16_t*)channel_data.data(), channel_data.size());
78   encoded_data.resize(encoded_size);
79 
80   // Encoder release
81   if (encoder_state != nullptr) {
82     g722_encode_release(encoder_state);
83     encoder_state = nullptr;
84   }
85 }
86 
fuzz_decode(FuzzedDataProvider * fdp)87 void fuzz_decode(FuzzedDataProvider* fdp) {
88   // Get values for primitive types from fdp
89   uint32_t rate = get_rate_from_fdp(fdp);
90   int options = fdp->ConsumeIntegral<int>();
91   uint16_t gain = fdp->ConsumeIntegral<uint16_t>();
92 
93   // Decoder Initialization
94   g722_decode_state_t* decoder_state = nullptr;
95   decoder_state = g722_decode_init(decoder_state, rate, options);
96 
97   std::vector<uint8_t> encoded_input = fdp->ConsumeRemainingBytes<uint8_t>();
98   int out_len =
99       encoded_input.size() * 2 /*bytes_per_sample*/ * 2 /*number of channels*/;
100 
101   // Decode
102   std::vector<int16_t> decoded_output;
103   decoded_output.resize(out_len);
104   int decoded_size = g722_decode(decoder_state, decoded_output.data(),
105                                  (const uint8_t*)encoded_input.data(),
106                                  encoded_input.size(), gain);
107   if (decoded_size > decoded_output.size()) {
108     abort();
109   }
110 
111   // Encoder release
112   if (decoder_state != nullptr) {
113     g722_decode_release(decoder_state);
114     decoder_state = nullptr;
115   }
116 }
117 }  // namespace
118 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)119 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
120   FuzzedDataProvider fdp(data, size);
121   fdp.ConsumeBool() ? fuzz_encode(&fdp) : fuzz_decode(&fdp);
122   return 0;
123 }
124