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 #include <android/binder_process.h>
17 #include <fcntl.h>
18 #include <fuzzer/FuzzedDataProvider.h>
19 #include <media/NdkMediaMuxer.h>
20 #include <sys/mman.h>
21 #include <unistd.h>
22
23 const std::string kMuxerFile = "mediaMuxer";
24 const std::string kAppendFile = "mediaAppend";
25 constexpr size_t kMinBytes = 0;
26 constexpr size_t kMaxBytes = 1000;
27 constexpr size_t kMinChoice = 0;
28 constexpr size_t kMaxChoice = 7;
29 constexpr size_t kMaxStringLength = 20;
30 constexpr size_t kOffset = 0;
31
32 constexpr OutputFormat kOutputFormat[] = {AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4,
33 AMEDIAMUXER_OUTPUT_FORMAT_WEBM,
34 AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP};
35 constexpr AppendMode kAppendMode[] = {AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP,
36 AMEDIAMUXER_APPEND_TO_EXISTING_DATA};
37
38 const std::string kAudioMimeType[] = {"audio/3gpp", "audio/amr-wb", "audio/mp4a-latm",
39 "audio/flac", "audio/vorbis", "audio/opus"};
40
41 const std::string kVideoMimeType[] = {"video/x-vnd.on2.vp8", "video/x-vnd.on2.vp9", "video/av01",
42 "video/avc", "video/hevc", "video/mp4v-es",
43 "video/3gpp"};
44
getSampleAudioFormat(FuzzedDataProvider & fdp,AMediaFormat * format)45 void getSampleAudioFormat(FuzzedDataProvider& fdp, AMediaFormat* format) {
46 std::string mimeType = fdp.ConsumeBool() ? fdp.ConsumeRandomLengthString(kMaxStringLength)
47 : fdp.PickValueInArray(kAudioMimeType);
48 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType.c_str());
49 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, fdp.ConsumeIntegral<int32_t>());
50 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, fdp.ConsumeIntegral<int32_t>());
51 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, fdp.ConsumeIntegral<int32_t>());
52 AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, fdp.ConsumeIntegral<int64_t>());
53 }
54
getSampleVideoFormat(FuzzedDataProvider & fdp,AMediaFormat * format)55 void getSampleVideoFormat(FuzzedDataProvider& fdp, AMediaFormat* format) {
56 std::string mimeType = fdp.ConsumeBool() ? fdp.ConsumeRandomLengthString(kMaxStringLength)
57 : fdp.PickValueInArray(kAudioMimeType);
58 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType.c_str());
59 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, fdp.ConsumeIntegral<int32_t>());
60 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, fdp.ConsumeIntegral<int32_t>());
61 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, fdp.ConsumeIntegral<int32_t>());
62 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, fdp.ConsumeIntegral<int32_t>());
63 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
64 fdp.ConsumeFloatingPoint<float>());
65 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_CAPTURE_RATE, fdp.ConsumeFloatingPoint<float>());
66 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, fdp.ConsumeIntegral<int32_t>());
67 }
68
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)69 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
70 /**
71 * Create a threadpool for incoming binder transactions,
72 * without this muxer results in a DoS after few instances.
73 */
74 ABinderProcess_startThreadPool();
75 FuzzedDataProvider fdp(data, size);
76 /**
77 * memfd_create() creates an anonymous file and returns a file
78 * descriptor that refers to it. MFD_ALLOW_SEALING allow sealing
79 * operations on this file.
80 */
81 int32_t fd = -1;
82 AMediaMuxer* muxer = nullptr;
83 if (fdp.ConsumeBool()) {
84 fd = memfd_create(kMuxerFile.c_str(), MFD_ALLOW_SEALING);
85 muxer = AMediaMuxer_new(fd, fdp.ConsumeBool()
86 ? fdp.PickValueInArray(kOutputFormat)
87 : (OutputFormat)fdp.ConsumeIntegral<int32_t>());
88 } else {
89 fd = memfd_create(kAppendFile.c_str(), MFD_ALLOW_SEALING);
90 std::vector<uint8_t> appendData =
91 fdp.ConsumeBytes<uint8_t>(fdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
92 write(fd, appendData.data(), appendData.size());
93 muxer = AMediaMuxer_append(fd, fdp.PickValueInArray(kAppendMode) /* mode */);
94 }
95 if (!muxer) {
96 close(fd);
97 return 0;
98 }
99 AMediaFormat* mediaFormat = nullptr;
100 ssize_t trackIdx = 0;
101 while (fdp.remaining_bytes()) {
102 int32_t kSwitchChoice = fdp.ConsumeIntegralInRange<int32_t>(kMinChoice, kMaxChoice);
103 switch (kSwitchChoice) {
104 case 0: {
105 AMediaMuxer_setLocation(muxer, fdp.ConsumeFloatingPoint<float>() /* latitude */,
106 fdp.ConsumeFloatingPoint<float>() /* longitude */);
107 break;
108 }
109 case 1: {
110 AMediaMuxer_setOrientationHint(muxer, fdp.ConsumeIntegral<int32_t>() /* degrees */);
111 break;
112 }
113 case 2: {
114 AMediaMuxer_start(muxer);
115 break;
116 }
117 case 3: {
118 AMediaMuxer_stop(muxer);
119 break;
120 }
121 case 4: {
122 AMediaMuxer_getTrackCount(muxer);
123 break;
124 }
125 case 5: {
126 AMediaFormat* getFormat =
127 AMediaMuxer_getTrackFormat(muxer, fdp.ConsumeIntegral<size_t>() /* idx */);
128 AMediaFormat_delete(getFormat);
129 break;
130 }
131 case 6: {
132 mediaFormat = AMediaFormat_new();
133 fdp.ConsumeBool() ? getSampleAudioFormat(fdp, mediaFormat)
134 : getSampleVideoFormat(fdp, mediaFormat);
135 trackIdx = AMediaMuxer_addTrack(muxer, mediaFormat);
136 AMediaFormat_delete(mediaFormat);
137 break;
138 }
139 default: {
140 std::vector<uint8_t> sampleData = fdp.ConsumeBytes<uint8_t>(
141 fdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
142 AMediaCodecBufferInfo codecBuffer;
143 codecBuffer.size = sampleData.size();
144 codecBuffer.offset = kOffset;
145 codecBuffer.presentationTimeUs = fdp.ConsumeIntegral<int64_t>();
146 codecBuffer.flags = fdp.ConsumeIntegral<uint32_t>();
147 AMediaMuxer_writeSampleData(
148 muxer,
149 fdp.ConsumeBool() ? trackIdx : fdp.ConsumeIntegral<size_t>() /* trackIdx */,
150 sampleData.data(), &codecBuffer);
151 break;
152 }
153 }
154 }
155 AMediaMuxer_delete(muxer);
156 close(fd);
157 return 0;
158 }
159