1 /*
2 Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved.
3
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice, this
8 list of conditions and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation and/or
12 other materials provided with the distribution.
13
14 3. Neither the name of the copyright holder nor the names of its contributors
15 may be used to endorse or promote products derived from this software without
16 specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <fcntl.h>
31
32 #if defined(_WIN32) || defined(__CYGWIN__)
33 #include <windows.h>
34 #else
35 #include <sys/mman.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #endif
39
40 #include <yara/error.h>
41 #include <yara/filemap.h>
42
43 ////////////////////////////////////////////////////////////////////////////////
44 // Maps a whole file into memory.
45 //
46 // Args:
47 // file_path: Path of the file to map.
48 // pmapped_file: Pointer to a YR_MAPPED_FILE that will be filled with
49 // information about the mapping.
50 // Returns:
51 // ERROR_SUCCESS
52 // ERROR_INVALID_ARGUMENT
53 // ERROR_COULD_NOT_OPEN_FILE
54 // ERROR_COULD_NOT_MAP_FILE
55 //
yr_filemap_map(const char * file_path,YR_MAPPED_FILE * pmapped_file)56 YR_API int yr_filemap_map(const char* file_path, YR_MAPPED_FILE* pmapped_file)
57 {
58 return yr_filemap_map_ex(file_path, 0, 0, pmapped_file);
59 }
60
61 ////////////////////////////////////////////////////////////////////////////////
62 // Maps a portion of a file (specified by descriptor) into memory.
63 //
64 // Args:
65 // file: File descriptor representing the file to map.
66 // offset: File offset where the mapping will begin. This offset must be
67 // multiple of 1MB and not greater than the actual file size.
68 // size: Number of bytes that will be mapped. If zero or greater than the
69 // actual file size all content until the end of the file will be
70 // mapped.
71 // pmapped_file: Pointer to a YR_MAPPED_FILE struct that will be filled with
72 // the new mapping.
73 // Returns:
74 // ERROR_SUCCESS
75 // ERROR_INVALID_ARGUMENT
76 // ERROR_COULD_NOT_OPEN_FILE
77 // ERROR_COULD_NOT_MAP_FILE
78 //
79 #if defined(_WIN32) || defined(__CYGWIN__)
80
yr_filemap_map_fd(YR_FILE_DESCRIPTOR file,uint64_t offset,size_t size,YR_MAPPED_FILE * pmapped_file)81 YR_API int yr_filemap_map_fd(
82 YR_FILE_DESCRIPTOR file,
83 uint64_t offset,
84 size_t size,
85 YR_MAPPED_FILE* pmapped_file)
86 {
87 LARGE_INTEGER fs;
88 size_t file_size;
89
90 pmapped_file->file = file;
91 pmapped_file->mapping = NULL;
92 pmapped_file->data = NULL;
93 pmapped_file->size = 0;
94
95 // Ensure that offset is aligned to 1MB
96 if (offset >> 20 << 20 != offset)
97 return ERROR_INVALID_ARGUMENT;
98
99 if (GetFileSizeEx(pmapped_file->file, &fs))
100 {
101 #ifdef _WIN64
102 file_size = fs.QuadPart;
103 #else
104 file_size = fs.LowPart;
105 #endif
106 }
107 else
108 {
109 pmapped_file->file = INVALID_HANDLE_VALUE;
110 return ERROR_COULD_NOT_OPEN_FILE;
111 }
112
113 if (offset > (uint64_t) file_size)
114 return ERROR_COULD_NOT_MAP_FILE;
115
116 if (size == 0)
117 size = (size_t)(file_size - offset);
118
119 pmapped_file->size = yr_min(size, (size_t)(file_size - offset));
120
121 if (pmapped_file->size != 0)
122 {
123 pmapped_file->mapping = CreateFileMapping(
124 pmapped_file->file, NULL, PAGE_READONLY, 0, 0, NULL);
125
126 if (pmapped_file->mapping == NULL)
127 {
128 pmapped_file->file = INVALID_HANDLE_VALUE;
129 pmapped_file->size = 0;
130 return ERROR_COULD_NOT_MAP_FILE;
131 }
132
133 pmapped_file->data = (const uint8_t*) MapViewOfFile(
134 pmapped_file->mapping,
135 FILE_MAP_READ,
136 offset >> 32,
137 offset & 0xFFFFFFFF,
138 pmapped_file->size);
139
140 if (pmapped_file->data == NULL)
141 {
142 CloseHandle(pmapped_file->mapping);
143 pmapped_file->mapping = NULL;
144 pmapped_file->file = INVALID_HANDLE_VALUE;
145 pmapped_file->size = 0;
146 return ERROR_COULD_NOT_MAP_FILE;
147 }
148 }
149 else
150 {
151 pmapped_file->mapping = NULL;
152 pmapped_file->data = NULL;
153 }
154
155 return ERROR_SUCCESS;
156 }
157
158 #else // POSIX
159
160 #define MAP_EXTRA_FLAGS 0
161
162 #if defined(__APPLE__)
163 // MacOS defines some extra flags for mmap.The MAP_RESILIENT_CODESIGN allows
164 // to read from binaries whose code signature is invalid, without this flags
165 // any attempt to read from such binaries causes a crash, see:
166 // https://github.com/VirusTotal/yara/issues/1309.
167 //
168 // Also, reading from files in removable media that becomes unavailable
169 // crashes the program if the MAP_RESILIENT_MEDIA flag is not set.
170 #if defined(MAP_RESILIENT_CODESIGN)
171 #undef MAP_EXTRA_FLAGS
172 #if defined(MAP_RESILIENT_MEDIA)
173 #define MAP_EXTRA_FLAGS MAP_RESILIENT_CODESIGN | MAP_RESILIENT_MEDIA
174 #else
175 #define MAP_EXTRA_FLAGS MAP_RESILIENT_CODESIGN
176 #endif
177 #endif // #if defined(MAP_RESILIENT_CODESIGN)
178 #endif // #if defined (__APPLE__)
179
yr_filemap_map_fd(YR_FILE_DESCRIPTOR file,uint64_t offset,size_t size,YR_MAPPED_FILE * pmapped_file)180 YR_API int yr_filemap_map_fd(
181 YR_FILE_DESCRIPTOR file,
182 uint64_t offset,
183 size_t size,
184 YR_MAPPED_FILE* pmapped_file)
185 {
186 struct stat st;
187
188 pmapped_file->file = file;
189 pmapped_file->data = NULL;
190 pmapped_file->size = 0;
191
192 // Ensure that offset is aligned to 1MB
193 if (offset >> 20 << 20 != offset)
194 return ERROR_INVALID_ARGUMENT;
195
196 if (fstat(file, &st) != 0 || S_ISDIR(st.st_mode))
197 return ERROR_COULD_NOT_OPEN_FILE;
198
199 if (offset > st.st_size)
200 return ERROR_COULD_NOT_MAP_FILE;
201
202 if (size == 0)
203 size = (size_t)(st.st_size - offset);
204
205 pmapped_file->size = yr_min(size, (size_t)(st.st_size - offset));
206
207 if (pmapped_file->size != 0)
208 {
209 pmapped_file->data = (const uint8_t*) mmap(
210 0,
211 pmapped_file->size,
212 PROT_READ,
213 MAP_PRIVATE | MAP_EXTRA_FLAGS,
214 pmapped_file->file,
215 offset);
216
217 if (pmapped_file->data == MAP_FAILED)
218 {
219 pmapped_file->data = NULL;
220 pmapped_file->size = 0;
221 pmapped_file->file = -1;
222
223 return ERROR_COULD_NOT_MAP_FILE;
224 }
225
226 madvise((void*) pmapped_file->data, pmapped_file->size, MADV_SEQUENTIAL);
227 }
228 else
229 {
230 pmapped_file->data = NULL;
231 }
232
233 return ERROR_SUCCESS;
234 }
235
236 #endif
237
238 ////////////////////////////////////////////////////////////////////////////////
239 // Maps a portion of a file (specified by path) into memory.
240 //
241 // Args:
242 // file_path: Path of the file to map.
243 // offset: File offset where the mapping will begin. This offset must be
244 // multiple of 1MB and not greater than the actual file size.
245 // size: Number of bytes that will be mapped. If zero or greater than the
246 // actual file size all content until the end of the file will be
247 // mapped.
248 // pmapped_file: Pointer to a YR_MAPPED_FILE struct that will be filled with
249 // the new mapping.
250 // Returns:
251 // ERROR_SUCCESS
252 // ERROR_INVALID_ARGUMENT
253 // ERROR_COULD_NOT_OPEN_FILE
254 // ERROR_COULD_NOT_MAP_FILE
255 //
256 #if defined(_WIN32) || defined(__CYGWIN__)
257
yr_filemap_map_ex(const char * file_path,uint64_t offset,size_t size,YR_MAPPED_FILE * pmapped_file)258 YR_API int yr_filemap_map_ex(
259 const char* file_path,
260 uint64_t offset,
261 size_t size,
262 YR_MAPPED_FILE* pmapped_file)
263 {
264 YR_FILE_DESCRIPTOR fd;
265 int result;
266
267 if (file_path == NULL)
268 return ERROR_INVALID_ARGUMENT;
269
270 fd = CreateFileA(
271 file_path,
272 GENERIC_READ,
273 FILE_SHARE_READ | FILE_SHARE_WRITE,
274 NULL,
275 OPEN_EXISTING,
276 FILE_FLAG_SEQUENTIAL_SCAN,
277 NULL);
278
279 if (fd == INVALID_HANDLE_VALUE)
280 return ERROR_COULD_NOT_OPEN_FILE;
281
282 result = yr_filemap_map_fd(fd, offset, size, pmapped_file);
283
284 if (result != ERROR_SUCCESS)
285 CloseHandle(fd);
286
287 return result;
288 }
289
290 #else // POSIX
291
yr_filemap_map_ex(const char * file_path,uint64_t offset,size_t size,YR_MAPPED_FILE * pmapped_file)292 YR_API int yr_filemap_map_ex(
293 const char* file_path,
294 uint64_t offset,
295 size_t size,
296 YR_MAPPED_FILE* pmapped_file)
297 {
298 YR_FILE_DESCRIPTOR fd;
299 int result;
300
301 if (file_path == NULL)
302 return ERROR_INVALID_ARGUMENT;
303
304 fd = open(file_path, O_RDONLY);
305
306 if (fd == -1)
307 return ERROR_COULD_NOT_OPEN_FILE;
308
309 result = yr_filemap_map_fd(fd, offset, size, pmapped_file);
310
311 if (result != ERROR_SUCCESS)
312 close(fd);
313
314 return result;
315 }
316
317 #endif
318
319 ////////////////////////////////////////////////////////////////////////////////
320 // Unmaps a file mapping.
321 //
322 // Args:
323 // pmapped_file: Pointer to a YR_MAPPED_FILE that struct.
324 //
325 #ifdef WIN32
326
yr_filemap_unmap_fd(YR_MAPPED_FILE * pmapped_file)327 YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file)
328 {
329 if (pmapped_file->data != NULL)
330 UnmapViewOfFile(pmapped_file->data);
331
332 if (pmapped_file->mapping != NULL)
333 CloseHandle(pmapped_file->mapping);
334
335 pmapped_file->mapping = NULL;
336 pmapped_file->data = NULL;
337 pmapped_file->size = 0;
338 }
339
yr_filemap_unmap(YR_MAPPED_FILE * pmapped_file)340 YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file)
341 {
342 yr_filemap_unmap_fd(pmapped_file);
343
344 if (pmapped_file->file != INVALID_HANDLE_VALUE)
345 {
346 CloseHandle(pmapped_file->file);
347 pmapped_file->file = INVALID_HANDLE_VALUE;
348 }
349 }
350
351 #else // POSIX
352
yr_filemap_unmap_fd(YR_MAPPED_FILE * pmapped_file)353 YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file)
354 {
355 if (pmapped_file->data != NULL)
356 munmap((void*) pmapped_file->data, pmapped_file->size);
357
358 pmapped_file->data = NULL;
359 pmapped_file->size = 0;
360 }
361
yr_filemap_unmap(YR_MAPPED_FILE * pmapped_file)362 YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file)
363 {
364 yr_filemap_unmap_fd(pmapped_file);
365
366 if (pmapped_file->file != -1)
367 {
368 close(pmapped_file->file);
369 pmapped_file->file = -1;
370 }
371 }
372
373 #endif
374