1*09537850SAkhilesh Sanikop /*
2*09537850SAkhilesh Sanikop * Copyright 2020 Google Inc.
3*09537850SAkhilesh Sanikop *
4*09537850SAkhilesh Sanikop * Licensed under the Apache License, Version 2.0 (the "License");
5*09537850SAkhilesh Sanikop * you may not use this file except in compliance with the License.
6*09537850SAkhilesh Sanikop * You may obtain a copy of the License at
7*09537850SAkhilesh Sanikop *
8*09537850SAkhilesh Sanikop * http://www.apache.org/licenses/LICENSE-2.0
9*09537850SAkhilesh Sanikop *
10*09537850SAkhilesh Sanikop * Unless required by applicable law or agreed to in writing, software
11*09537850SAkhilesh Sanikop * distributed under the License is distributed on an "AS IS" BASIS,
12*09537850SAkhilesh Sanikop * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*09537850SAkhilesh Sanikop * See the License for the specific language governing permissions and
14*09537850SAkhilesh Sanikop * limitations under the License.
15*09537850SAkhilesh Sanikop */
16*09537850SAkhilesh Sanikop
17*09537850SAkhilesh Sanikop #ifndef LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
18*09537850SAkhilesh Sanikop #define LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
19*09537850SAkhilesh Sanikop
20*09537850SAkhilesh Sanikop // Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
21*09537850SAkhilesh Sanikop // require a file instead of an input buffer.
22*09537850SAkhilesh Sanikop
23*09537850SAkhilesh Sanikop #include <limits.h>
24*09537850SAkhilesh Sanikop #include <stdint.h>
25*09537850SAkhilesh Sanikop #include <stdio.h>
26*09537850SAkhilesh Sanikop #include <stdlib.h>
27*09537850SAkhilesh Sanikop #include <string.h>
28*09537850SAkhilesh Sanikop #ifdef _WIN32
29*09537850SAkhilesh Sanikop #include <io.h>
30*09537850SAkhilesh Sanikop #include <windows.h>
31*09537850SAkhilesh Sanikop
32*09537850SAkhilesh Sanikop #define strdup _strdup
33*09537850SAkhilesh Sanikop #define unlink _unlink
34*09537850SAkhilesh Sanikop #else
35*09537850SAkhilesh Sanikop #include <unistd.h>
36*09537850SAkhilesh Sanikop #endif // _WIN32
37*09537850SAkhilesh Sanikop
38*09537850SAkhilesh Sanikop // Pure-C interface for creating and cleaning up temporary files.
39*09537850SAkhilesh Sanikop
fuzzer_get_tmpfile_with_suffix(const uint8_t * data,size_t size,const char * suffix)40*09537850SAkhilesh Sanikop static char* fuzzer_get_tmpfile_with_suffix(const uint8_t* data, size_t size,
41*09537850SAkhilesh Sanikop const char* suffix) {
42*09537850SAkhilesh Sanikop #ifdef _WIN32
43*09537850SAkhilesh Sanikop // GetTempPathA generates '<path>\<pre><uuuu>.TMP'.
44*09537850SAkhilesh Sanikop (void)suffix; // NOLINT (this could be a C compilation unit)
45*09537850SAkhilesh Sanikop char temp_path[MAX_PATH];
46*09537850SAkhilesh Sanikop const DWORD ret = GetTempPathA(MAX_PATH, temp_path);
47*09537850SAkhilesh Sanikop if (ret == 0 || ret > MAX_PATH) {
48*09537850SAkhilesh Sanikop fprintf(stderr, "Error getting temporary directory name: %lu\n",
49*09537850SAkhilesh Sanikop GetLastError());
50*09537850SAkhilesh Sanikop abort();
51*09537850SAkhilesh Sanikop }
52*09537850SAkhilesh Sanikop char* filename_buffer =
53*09537850SAkhilesh Sanikop (char*)malloc(MAX_PATH); // NOLINT (this could be a C compilation unit)
54*09537850SAkhilesh Sanikop if (!filename_buffer) {
55*09537850SAkhilesh Sanikop perror("Failed to allocate file name buffer.");
56*09537850SAkhilesh Sanikop abort();
57*09537850SAkhilesh Sanikop }
58*09537850SAkhilesh Sanikop if (GetTempFileNameA(temp_path, "ftf", /*uUnique=*/0, filename_buffer) == 0) {
59*09537850SAkhilesh Sanikop fprintf(stderr, "Error getting temporary file name: %lu\n", GetLastError());
60*09537850SAkhilesh Sanikop abort();
61*09537850SAkhilesh Sanikop }
62*09537850SAkhilesh Sanikop #if defined(_MSC_VER) || defined(MINGW_HAS_SECURE_API)
63*09537850SAkhilesh Sanikop FILE* file;
64*09537850SAkhilesh Sanikop const errno_t err = fopen_s(&file, filename_buffer, "wb");
65*09537850SAkhilesh Sanikop if (err != 0) file = NULL; // NOLINT (this could be a C compilation unit)
66*09537850SAkhilesh Sanikop #else
67*09537850SAkhilesh Sanikop FILE* file = fopen(filename_buffer, "wb");
68*09537850SAkhilesh Sanikop #endif
69*09537850SAkhilesh Sanikop if (!file) {
70*09537850SAkhilesh Sanikop perror("Failed to open file.");
71*09537850SAkhilesh Sanikop abort();
72*09537850SAkhilesh Sanikop }
73*09537850SAkhilesh Sanikop #else // !_WIN32
74*09537850SAkhilesh Sanikop if (suffix == NULL) { // NOLINT (this could be a C compilation unit)
75*09537850SAkhilesh Sanikop suffix = "";
76*09537850SAkhilesh Sanikop }
77*09537850SAkhilesh Sanikop const size_t suffix_len = strlen(suffix);
78*09537850SAkhilesh Sanikop if (suffix_len > INT_MAX) { // mkstemps takes int for suffixlen param
79*09537850SAkhilesh Sanikop perror("Suffix too long");
80*09537850SAkhilesh Sanikop abort();
81*09537850SAkhilesh Sanikop }
82*09537850SAkhilesh Sanikop
83*09537850SAkhilesh Sanikop #ifdef __ANDROID__
84*09537850SAkhilesh Sanikop const char* leading_temp_path =
85*09537850SAkhilesh Sanikop "/data/local/tmp/generate_temporary_file.XXXXXX";
86*09537850SAkhilesh Sanikop #else
87*09537850SAkhilesh Sanikop const char* leading_temp_path = "/tmp/generate_temporary_file.XXXXXX";
88*09537850SAkhilesh Sanikop #endif
89*09537850SAkhilesh Sanikop const size_t buffer_sz = strlen(leading_temp_path) + suffix_len + 1;
90*09537850SAkhilesh Sanikop char* filename_buffer =
91*09537850SAkhilesh Sanikop (char*)malloc(buffer_sz); // NOLINT (this could be a C compilation unit)
92*09537850SAkhilesh Sanikop if (!filename_buffer) {
93*09537850SAkhilesh Sanikop perror("Failed to allocate file name buffer.");
94*09537850SAkhilesh Sanikop abort();
95*09537850SAkhilesh Sanikop }
96*09537850SAkhilesh Sanikop
97*09537850SAkhilesh Sanikop if (snprintf(filename_buffer, buffer_sz, "%s%s", leading_temp_path, suffix) >=
98*09537850SAkhilesh Sanikop (int)buffer_sz) { // NOLINT (this could be a C compilation unit)
99*09537850SAkhilesh Sanikop perror("File name buffer too short.");
100*09537850SAkhilesh Sanikop abort();
101*09537850SAkhilesh Sanikop }
102*09537850SAkhilesh Sanikop
103*09537850SAkhilesh Sanikop const int file_descriptor = mkstemps(filename_buffer, suffix_len);
104*09537850SAkhilesh Sanikop if (file_descriptor < 0) {
105*09537850SAkhilesh Sanikop perror("Failed to make temporary file.");
106*09537850SAkhilesh Sanikop abort();
107*09537850SAkhilesh Sanikop }
108*09537850SAkhilesh Sanikop FILE* file = fdopen(file_descriptor, "wb");
109*09537850SAkhilesh Sanikop if (!file) {
110*09537850SAkhilesh Sanikop perror("Failed to open file descriptor.");
111*09537850SAkhilesh Sanikop close(file_descriptor);
112*09537850SAkhilesh Sanikop abort();
113*09537850SAkhilesh Sanikop }
114*09537850SAkhilesh Sanikop #endif // _WIN32
115*09537850SAkhilesh Sanikop const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
116*09537850SAkhilesh Sanikop if (bytes_written < size) {
117*09537850SAkhilesh Sanikop fclose(file);
118*09537850SAkhilesh Sanikop fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
119*09537850SAkhilesh Sanikop bytes_written, size);
120*09537850SAkhilesh Sanikop abort();
121*09537850SAkhilesh Sanikop }
122*09537850SAkhilesh Sanikop fclose(file);
123*09537850SAkhilesh Sanikop return filename_buffer;
124*09537850SAkhilesh Sanikop }
125*09537850SAkhilesh Sanikop
fuzzer_get_tmpfile(const uint8_t * data,size_t size)126*09537850SAkhilesh Sanikop static char* fuzzer_get_tmpfile(
127*09537850SAkhilesh Sanikop const uint8_t* data,
128*09537850SAkhilesh Sanikop size_t size) { // NOLINT (people include this .inc file directly)
129*09537850SAkhilesh Sanikop return fuzzer_get_tmpfile_with_suffix(data, size, NULL); // NOLINT
130*09537850SAkhilesh Sanikop }
131*09537850SAkhilesh Sanikop
fuzzer_release_tmpfile(char * filename)132*09537850SAkhilesh Sanikop static void fuzzer_release_tmpfile(char* filename) {
133*09537850SAkhilesh Sanikop if (unlink(filename) != 0) {
134*09537850SAkhilesh Sanikop perror("WARNING: Failed to delete temporary file.");
135*09537850SAkhilesh Sanikop }
136*09537850SAkhilesh Sanikop free(filename);
137*09537850SAkhilesh Sanikop }
138*09537850SAkhilesh Sanikop
139*09537850SAkhilesh Sanikop // C++ RAII object for creating temporary files.
140*09537850SAkhilesh Sanikop
141*09537850SAkhilesh Sanikop #ifdef __cplusplus
142*09537850SAkhilesh Sanikop class FuzzerTemporaryFile {
143*09537850SAkhilesh Sanikop public:
FuzzerTemporaryFile(const uint8_t * data,size_t size)144*09537850SAkhilesh Sanikop FuzzerTemporaryFile(const uint8_t* data, size_t size)
145*09537850SAkhilesh Sanikop : original_filename_(fuzzer_get_tmpfile(data, size)) {
146*09537850SAkhilesh Sanikop filename_ = strdup(original_filename_);
147*09537850SAkhilesh Sanikop if (!filename_) {
148*09537850SAkhilesh Sanikop perror("Failed to allocate file name copy.");
149*09537850SAkhilesh Sanikop abort();
150*09537850SAkhilesh Sanikop }
151*09537850SAkhilesh Sanikop }
152*09537850SAkhilesh Sanikop
FuzzerTemporaryFile(const uint8_t * data,size_t size,const char * suffix)153*09537850SAkhilesh Sanikop FuzzerTemporaryFile(const uint8_t* data, size_t size, const char* suffix)
154*09537850SAkhilesh Sanikop : original_filename_(fuzzer_get_tmpfile_with_suffix(data, size, suffix)) {
155*09537850SAkhilesh Sanikop filename_ = strdup(original_filename_);
156*09537850SAkhilesh Sanikop if (!filename_) {
157*09537850SAkhilesh Sanikop perror("Failed to allocate file name copy.");
158*09537850SAkhilesh Sanikop abort();
159*09537850SAkhilesh Sanikop }
160*09537850SAkhilesh Sanikop }
161*09537850SAkhilesh Sanikop
~FuzzerTemporaryFile()162*09537850SAkhilesh Sanikop ~FuzzerTemporaryFile() {
163*09537850SAkhilesh Sanikop free(filename_);
164*09537850SAkhilesh Sanikop fuzzer_release_tmpfile(original_filename_);
165*09537850SAkhilesh Sanikop }
166*09537850SAkhilesh Sanikop
167*09537850SAkhilesh Sanikop FuzzerTemporaryFile(const FuzzerTemporaryFile& other) = delete;
168*09537850SAkhilesh Sanikop FuzzerTemporaryFile operator=(const FuzzerTemporaryFile& other) = delete;
169*09537850SAkhilesh Sanikop
170*09537850SAkhilesh Sanikop FuzzerTemporaryFile(const FuzzerTemporaryFile&& other) = delete;
171*09537850SAkhilesh Sanikop FuzzerTemporaryFile operator=(const FuzzerTemporaryFile&& other) = delete;
172*09537850SAkhilesh Sanikop
filename()173*09537850SAkhilesh Sanikop const char* filename() const { return filename_; }
174*09537850SAkhilesh Sanikop
175*09537850SAkhilesh Sanikop // Returns a mutable pointer to the file name. Should be used sparingly, only
176*09537850SAkhilesh Sanikop // in case the fuzzed API demands it or when making a mutable copy is
177*09537850SAkhilesh Sanikop // inconvenient (e.g., in auto-generated code).
mutable_filename()178*09537850SAkhilesh Sanikop char* mutable_filename() const { return filename_; }
179*09537850SAkhilesh Sanikop
180*09537850SAkhilesh Sanikop private:
181*09537850SAkhilesh Sanikop char* original_filename_;
182*09537850SAkhilesh Sanikop
183*09537850SAkhilesh Sanikop // A mutable copy of the original filename, returned by the accessor. This
184*09537850SAkhilesh Sanikop // guarantees that the original filename can always be used to release the
185*09537850SAkhilesh Sanikop // temporary path.
186*09537850SAkhilesh Sanikop char* filename_;
187*09537850SAkhilesh Sanikop };
188*09537850SAkhilesh Sanikop #endif // __cplusplus
189*09537850SAkhilesh Sanikop #endif // LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
190