Coverage Report

Created: 2023-03-26 07:37

/src/yara/libyara/filemap.c
Line
Count
Source (jump to first uncovered line)
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
//
56
YR_API int yr_filemap_map(const char* file_path, YR_MAPPED_FILE* pmapped_file)
57
0
{
58
0
  return yr_filemap_map_ex(file_path, 0, 0, pmapped_file);
59
0
}
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
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
#ifdef __linux__
161
#include <sys/vfs.h>
162
#include <linux/magic.h>
163
#endif
164
165
0
#define MAP_EXTRA_FLAGS 0
166
167
#if defined(__APPLE__)
168
// MacOS defines some extra flags for mmap.The MAP_RESILIENT_CODESIGN allows
169
// to read from binaries whose code signature is invalid, without this flags
170
// any attempt to read from such binaries causes a crash, see:
171
// https://github.com/VirusTotal/yara/issues/1309.
172
//
173
// Also, reading from files in removable media that becomes unavailable
174
// crashes the program if the MAP_RESILIENT_MEDIA flag is not set.
175
#if defined(MAP_RESILIENT_CODESIGN)
176
#undef MAP_EXTRA_FLAGS
177
#if defined(MAP_RESILIENT_MEDIA)
178
#define MAP_EXTRA_FLAGS MAP_RESILIENT_CODESIGN | MAP_RESILIENT_MEDIA
179
#else
180
#define MAP_EXTRA_FLAGS MAP_RESILIENT_CODESIGN
181
#endif
182
#endif  // #if defined(MAP_RESILIENT_CODESIGN)
183
#endif  // #if defined (__APPLE__)
184
185
YR_API int yr_filemap_map_fd(
186
    YR_FILE_DESCRIPTOR file,
187
    uint64_t offset,
188
    size_t size,
189
    YR_MAPPED_FILE* pmapped_file)
190
0
{
191
0
  struct stat st;
192
0
#ifdef __linux__
193
0
  struct statfs stfs;
194
0
#endif
195
196
0
  pmapped_file->file = file;
197
0
  pmapped_file->data = NULL;
198
0
  pmapped_file->size = 0;
199
200
  // Ensure that offset is aligned to 1MB
201
0
  if (offset >> 20 << 20 != offset)
202
0
    return ERROR_INVALID_ARGUMENT;
203
204
0
  if (fstat(file, &st) != 0 || S_ISDIR(st.st_mode))
205
0
    return ERROR_COULD_NOT_OPEN_FILE;
206
207
0
  if (offset > st.st_size)
208
0
    return ERROR_COULD_NOT_MAP_FILE;
209
210
0
#ifdef __linux__
211
0
  if (fstatfs(file, &stfs) != 0)
212
0
    return ERROR_COULD_NOT_OPEN_FILE;
213
214
0
  switch (stfs.f_type) {
215
0
  case PROC_SUPER_MAGIC:
216
0
    return ERROR_COULD_NOT_OPEN_FILE;
217
0
  }
218
0
#endif
219
220
0
  if (size == 0)
221
0
    size = (size_t)(st.st_size - offset);
222
223
0
  pmapped_file->size = yr_min(size, (size_t)(st.st_size - offset));
224
225
0
  if (pmapped_file->size != 0)
226
0
  {
227
0
    pmapped_file->data = (const uint8_t*) mmap(
228
0
        0,
229
0
        pmapped_file->size,
230
0
        PROT_READ,
231
0
        MAP_PRIVATE | MAP_EXTRA_FLAGS,
232
0
        pmapped_file->file,
233
0
        offset);
234
235
0
    if (pmapped_file->data == MAP_FAILED)
236
0
    {
237
0
      pmapped_file->data = NULL;
238
0
      pmapped_file->size = 0;
239
0
      pmapped_file->file = -1;
240
241
0
      return ERROR_COULD_NOT_MAP_FILE;
242
0
    }
243
244
0
    madvise((void*) pmapped_file->data, pmapped_file->size, MADV_SEQUENTIAL);
245
0
  }
246
0
  else
247
0
  {
248
0
    pmapped_file->data = NULL;
249
0
  }
250
251
0
  return ERROR_SUCCESS;
252
0
}
253
254
#endif
255
256
////////////////////////////////////////////////////////////////////////////////
257
// Maps a portion of a file (specified by path) into memory.
258
//
259
// Args:
260
//   file_path: Path of the file to map.
261
//   offset: File offset where the mapping will begin. This offset must be
262
//           multiple of 1MB and not greater than the actual file size.
263
//   size: Number of bytes that will be mapped. If zero or greater than the
264
//         actual file size all content until the end of the file will be
265
//         mapped.
266
//   pmapped_file: Pointer to a YR_MAPPED_FILE struct that will be filled with
267
//                 the new mapping.
268
// Returns:
269
//   ERROR_SUCCESS
270
//   ERROR_INVALID_ARGUMENT
271
//   ERROR_COULD_NOT_OPEN_FILE
272
//   ERROR_COULD_NOT_MAP_FILE
273
//
274
#if defined(_WIN32) || defined(__CYGWIN__)
275
276
YR_API int yr_filemap_map_ex(
277
    const char* file_path,
278
    uint64_t offset,
279
    size_t size,
280
    YR_MAPPED_FILE* pmapped_file)
281
{
282
  YR_FILE_DESCRIPTOR fd;
283
  int result;
284
285
  if (file_path == NULL)
286
    return ERROR_INVALID_ARGUMENT;
287
288
  fd = CreateFileA(
289
      file_path,
290
      GENERIC_READ,
291
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
292
      NULL,
293
      OPEN_EXISTING,
294
      FILE_FLAG_SEQUENTIAL_SCAN,
295
      NULL);
296
297
  if (fd == INVALID_HANDLE_VALUE)
298
    return ERROR_COULD_NOT_OPEN_FILE;
299
300
  result = yr_filemap_map_fd(fd, offset, size, pmapped_file);
301
302
  if (result != ERROR_SUCCESS)
303
    CloseHandle(fd);
304
305
  return result;
306
}
307
308
#else  // POSIX
309
310
YR_API int yr_filemap_map_ex(
311
    const char* file_path,
312
    uint64_t offset,
313
    size_t size,
314
    YR_MAPPED_FILE* pmapped_file)
315
0
{
316
0
  YR_FILE_DESCRIPTOR fd;
317
0
  int result;
318
319
0
  if (file_path == NULL)
320
0
    return ERROR_INVALID_ARGUMENT;
321
322
0
  fd = open(file_path, O_RDONLY);
323
324
0
  if (fd == -1)
325
0
    return ERROR_COULD_NOT_OPEN_FILE;
326
327
0
  result = yr_filemap_map_fd(fd, offset, size, pmapped_file);
328
329
0
  if (result != ERROR_SUCCESS)
330
0
    close(fd);
331
332
0
  return result;
333
0
}
334
335
#endif
336
337
////////////////////////////////////////////////////////////////////////////////
338
// Unmaps a file mapping.
339
//
340
// Args:
341
//   pmapped_file: Pointer to a YR_MAPPED_FILE that struct.
342
//
343
#ifdef WIN32
344
345
YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file)
346
{
347
  if (pmapped_file->data != NULL)
348
    UnmapViewOfFile(pmapped_file->data);
349
350
  if (pmapped_file->mapping != NULL)
351
    CloseHandle(pmapped_file->mapping);
352
353
  pmapped_file->mapping = NULL;
354
  pmapped_file->data = NULL;
355
  pmapped_file->size = 0;
356
}
357
358
YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file)
359
{
360
  yr_filemap_unmap_fd(pmapped_file);
361
362
  if (pmapped_file->file != INVALID_HANDLE_VALUE)
363
  {
364
    CloseHandle(pmapped_file->file);
365
    pmapped_file->file = INVALID_HANDLE_VALUE;
366
  }
367
}
368
369
#else  // POSIX
370
371
YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file)
372
0
{
373
0
  if (pmapped_file->data != NULL)
374
0
    munmap((void*) pmapped_file->data, pmapped_file->size);
375
376
0
  pmapped_file->data = NULL;
377
0
  pmapped_file->size = 0;
378
0
}
379
380
YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file)
381
0
{
382
0
  yr_filemap_unmap_fd(pmapped_file);
383
384
0
  if (pmapped_file->file != -1)
385
0
  {
386
0
    close(pmapped_file->file);
387
0
    pmapped_file->file = -1;
388
0
  }
389
0
}
390
391
#endif