• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google Inc.
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 #ifndef LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
18 #define LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
19 
20 // Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
21 // require a file instead of an input buffer.
22 
23 #include <limits.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 // Pure-C interface for creating and cleaning up temporary files.
31 
fuzzer_get_tmpfile_with_suffix(const uint8_t * data,size_t size,const char * suffix)32 static char* fuzzer_get_tmpfile_with_suffix(const uint8_t* data, size_t size,
33                                             const char* suffix) {
34   if (suffix == NULL) {  // NOLINT (this could be a C compilation unit)
35     suffix = "";
36   }
37   const size_t suffix_len = strlen(suffix);
38   if (suffix_len > INT_MAX) {  // mkstemps takes int for suffixlen param
39     perror("Suffix too long");
40     abort();
41   }
42 
43 #ifdef __ANDROID__
44   const char* leading_temp_path =
45       "/data/local/tmp/generate_temporary_file.XXXXXX";
46 #else
47   const char* leading_temp_path = "/tmp/generate_temporary_file.XXXXXX";
48 #endif
49   const size_t buffer_sz = strlen(leading_temp_path) + suffix_len + 1;
50   char* filename_buffer =
51       (char*)malloc(buffer_sz);  // NOLINT (this could be a C compilation unit)
52   if (!filename_buffer) {
53     perror("Failed to allocate file name buffer.");
54     abort();
55   }
56 
57   if (snprintf(filename_buffer, buffer_sz, "%s%s", leading_temp_path, suffix) >=
58       buffer_sz) {
59     perror("File name buffer too short.");
60     abort();
61   }
62 
63   const int file_descriptor = mkstemps(filename_buffer, suffix_len);
64   if (file_descriptor < 0) {
65     perror("Failed to make temporary file.");
66     abort();
67   }
68   FILE* file = fdopen(file_descriptor, "wb");
69   if (!file) {
70     perror("Failed to open file descriptor.");
71     close(file_descriptor);
72     abort();
73   }
74   const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
75   if (bytes_written < size) {
76     close(file_descriptor);
77     fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
78             bytes_written, size);
79     abort();
80   }
81   fclose(file);
82   return filename_buffer;
83 }
84 
fuzzer_get_tmpfile(const uint8_t * data,size_t size)85 static char* fuzzer_get_tmpfile(
86     const uint8_t* data,
87     size_t size) {  // NOLINT (people include this .inc file directly)
88   return fuzzer_get_tmpfile_with_suffix(data, size, NULL);  // NOLINT
89 }
90 
fuzzer_release_tmpfile(char * filename)91 static void fuzzer_release_tmpfile(char* filename) {
92   if (unlink(filename) != 0) {
93     perror("WARNING: Failed to delete temporary file.");
94   }
95   free(filename);
96 }
97 
98 // C++ RAII object for creating temporary files.
99 
100 #ifdef __cplusplus
101 class FuzzerTemporaryFile {
102  public:
FuzzerTemporaryFile(const uint8_t * data,size_t size)103   FuzzerTemporaryFile(const uint8_t* data, size_t size)
104       : original_filename_(fuzzer_get_tmpfile(data, size)) {
105     filename_ = strdup(original_filename_);
106     if (!filename_) {
107       perror("Failed to allocate file name copy.");
108       abort();
109     }
110   }
111 
FuzzerTemporaryFile(const uint8_t * data,size_t size,const char * suffix)112   FuzzerTemporaryFile(const uint8_t* data, size_t size, const char* suffix)
113       : original_filename_(fuzzer_get_tmpfile_with_suffix(data, size, suffix)) {
114     filename_ = strdup(original_filename_);
115     if (!filename_) {
116       perror("Failed to allocate file name copy.");
117       abort();
118     }
119   }
120 
~FuzzerTemporaryFile()121   ~FuzzerTemporaryFile() {
122     free(filename_);
123     fuzzer_release_tmpfile(original_filename_);
124   }
125 
126   FuzzerTemporaryFile(const FuzzerTemporaryFile& other) = delete;
127   FuzzerTemporaryFile operator=(const FuzzerTemporaryFile& other) = delete;
128 
129   FuzzerTemporaryFile(const FuzzerTemporaryFile&& other) = delete;
130   FuzzerTemporaryFile operator=(const FuzzerTemporaryFile&& other) = delete;
131 
filename()132   const char* filename() const { return filename_; }
133 
134   // Returns a mutable pointer to the file name. Should be used sparingly, only
135   // in case the fuzzed API demands it or when making a mutable copy is
136   // inconvenient (e.g., in auto-generated code).
mutable_filename()137   char* mutable_filename() const { return filename_; }
138 
139  private:
140   char* original_filename_;
141 
142   // A mutable copy of the original filename, returned by the accessor. This
143   // guarantees that the original filename can always be used to release the
144   // temporary path.
145   char* filename_;
146 };
147 #endif  // __cplusplus
148 #endif  // LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
149