Coverage Report

Created: 2025-08-26 06:33

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