suricata
util-magic.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Wrappers and tests for libmagic usage.
24  *
25  * Libmagic's API is not thread safe. The data the pointer returned by
26  * magic_buffer is overwritten by the next magic_buffer call. This is
27  * why we need to lock calls and copy the returned string.
28  */
29 
30 #include "suricata-common.h"
31 #include "conf.h"
32 #include "util-magic.h"
33 #include "util-debug.h"
34 
35 #ifdef HAVE_MAGIC
36 
37 /**
38  * \brief Initialize a "magic" context.
39  */
40 magic_t MagicInitContext(void)
41 {
42  magic_t ctx;
43  const char *filename = NULL;
44  FILE *fd = NULL;
45 
46  ctx = magic_open(0);
47  if (ctx == NULL) {
48  SCLogError("magic_open failed: %s", magic_error(ctx));
49  goto error;
50  }
51 
52  (void)SCConfGet("magic-file", &filename);
53 
54  if (filename != NULL) {
55  if (strlen(filename) == 0) {
56  /* set filename to NULL on *nix systems so magic_load uses system
57  * default path (see man libmagic) */
58  SCLogConfig("using system default magic-file");
59  filename = NULL;
60  }
61  else {
62  SCLogConfig("using magic-file %s", filename);
63 
64  if ( (fd = fopen(filename, "r")) == NULL) {
65  SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno));
66  goto error;
67  }
68  fclose(fd);
69  }
70  }
71 
72  if (magic_load(ctx, filename) != 0) {
73  SCLogError("magic_load failed: %s", magic_error(ctx));
74  goto error;
75  }
76  return ctx;
77 
78 error:
79  if (ctx != NULL) {
80  magic_close(ctx);
81  ctx = NULL;
82  }
83  return NULL;
84 }
85 
86 
87 void MagicDeinitContext(magic_t ctx)
88 {
89  if (ctx != NULL)
90  magic_close(ctx);
91 }
92 
93 /**
94  * \brief Find the magic value for a buffer.
95  *
96  * \param buf the buffer
97  * \param buflen length of the buffer
98  *
99  * \retval result pointer to null terminated string
100  */
101 char *MagicThreadLookup(magic_t *ctx, const uint8_t *buf, uint32_t buflen)
102 {
103  const char *result = NULL;
104  char *magic = NULL;
105 
106  if (buf != NULL && buflen > 0) {
107  result = magic_buffer(*ctx, (void *)buf, (size_t)buflen);
108  if (result != NULL) {
109  magic = SCStrdup(result);
110  if (unlikely(magic == NULL)) {
111  SCLogError("Unable to dup magic");
112  }
113  }
114  }
115 
116  SCReturnPtr(magic, "const char");
117 }
118 
119 #ifdef UNITTESTS
120 
121 /** \test magic lib calls -- init */
122 static int MagicInitTest01(void)
123 {
124  magic_t magic_ctx = magic_open(0);
125  FAIL_IF_NULL(magic_ctx);
126  FAIL_IF(magic_load(magic_ctx, NULL) == -1);
127  magic_close(magic_ctx);
128  PASS;
129 }
130 
131 /** \test magic lib calls -- lookup */
132 static int MagicDetectTest01(void)
133 {
134  char buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a};
135  size_t buffer_len = sizeof(buffer);
136 
137  magic_t magic_ctx = magic_open(0);
138  FAIL_IF_NULL(magic_ctx);
139  FAIL_IF(magic_load(magic_ctx, NULL) == -1);
140 
141  char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len);
142  FAIL_IF_NULL(result);
143  FAIL_IF(strncmp(result, "PDF document", 12) != 0);
144  magic_close(magic_ctx);
145  PASS;
146 }
147 
148 /** \test magic lib calls -- lookup */
149 static int MagicDetectTest03(void)
150 {
151  char buffer[] = {
152  0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00,
153  0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6,
154  0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00,
155  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69,
156 
157  0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70,
158  0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
159  0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61,
160  0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e,
161 
162  0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
163  0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03,
164  0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b,
165  0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
166 
167  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a,
168  0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69,
169  0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
170  0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75,
171 
172  0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03,
173  0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b,
174  };
175  size_t buffer_len = sizeof(buffer);
176 
177  magic_t magic_ctx = magic_open(0);
178  FAIL_IF_NULL(magic_ctx);
179 
180  FAIL_IF(magic_load(magic_ctx, NULL) == -1);
181 
182  char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len);
183  FAIL_IF_NULL(result);
184 
185  char *str = strstr(result, "OpenDocument Text");
186  FAIL_IF_NULL(str);
187 
188  magic_close(magic_ctx);
189  PASS;
190 }
191 
192 /** \test magic lib calls -- lookup */
193 static int MagicDetectTest04(void)
194 {
195  char buffer[] = {
196  0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08,
197  0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70,
198  0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00,
199  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69,
200 
201  0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70,
202  0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
203  0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75,
204  0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61,
205 
206  0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00,
207  0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c,
208  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209  0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
210 
211  0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46,
212  0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00,
213  0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d,
214  0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e,
215 
216  0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63,
217  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78,
218  0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30,
219  0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c,
220 
221  0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29,
222  0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43,
223  0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15,
224  };
225  size_t buffer_len = sizeof(buffer);
226 
227  magic_t magic_ctx = magic_open(0);
228  FAIL_IF_NULL(magic_ctx);
229  FAIL_IF(magic_load(magic_ctx, NULL) == -1);
230 
231  char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len);
232  FAIL_IF_NULL(result);
233  FAIL_IF(strncmp(result, "OpenOffice.org 1.x", 18) != 0);
234  magic_close(magic_ctx);
235  PASS;
236 }
237 
238 /** \test magic api calls -- lookup */
239 static int MagicDetectTest05(void)
240 {
241  uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a};
242  size_t buffer_len = sizeof(buffer);
243 
244  magic_t ctx = MagicInitContext();
245  FAIL_IF(ctx == NULL);
246 
247  char *result = MagicThreadLookup(&ctx, buffer, buffer_len);
248  FAIL_IF_NULL(result);
249  FAIL_IF(strncmp(result, "PDF document", 12) != 0);
250  MagicDeinitContext(ctx);
251  SCFree(result);
252  PASS;
253 }
254 
255 /** \test magic api calls -- lookup */
256 static int MagicDetectTest07(void)
257 {
258  uint8_t buffer[] = {
259  0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00,
260  0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6,
261  0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00,
262  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69,
263 
264  0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70,
265  0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
266  0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61,
267  0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e,
268 
269  0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
270  0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03,
271  0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b,
272  0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
273 
274  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a,
275  0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69,
276  0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
277  0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75,
278 
279  0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03,
280  0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b,
281  };
282  size_t buffer_len = sizeof(buffer);
283 
284  magic_t ctx = MagicInitContext();
285  FAIL_IF(ctx == NULL);
286 
287  char *result = MagicThreadLookup(&ctx, buffer, buffer_len);
288  FAIL_IF_NULL(result);
289 
290  char *str = strstr(result, "OpenDocument Text");
291  FAIL_IF_NULL(str);
292  SCFree(result);
293 
294  MagicDeinitContext(ctx);
295  PASS;
296 }
297 
298 /** \test magic api calls -- lookup */
299 static int MagicDetectTest08(void)
300 {
301  uint8_t buffer[] = {
302  0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08,
303  0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70,
304  0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00,
305  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69,
306 
307  0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70,
308  0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
309  0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75,
310  0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61,
311 
312  0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00,
313  0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c,
314  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315  0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
316 
317  0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46,
318  0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00,
319  0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d,
320  0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e,
321 
322  0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63,
323  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78,
324  0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30,
325 
326  0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c,
327  0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29,
328  0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43,
329  0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15,
330  };
331  size_t buffer_len = sizeof(buffer);
332 
333  magic_t ctx = MagicInitContext();
334  FAIL_IF(ctx == NULL);
335 
336  char *result = MagicThreadLookup(&ctx, buffer, buffer_len);
337  FAIL_IF_NULL(result);
338  FAIL_IF(strncmp(result, "OpenOffice.org 1.x", 18) != 0);
339  SCFree(result);
340  MagicDeinitContext(ctx);
341  PASS;
342 }
343 
344 /** \test results in valgrind warning about invalid read, tested with
345  * file 5.09 and 5.11 */
346 static int MagicDetectTest10ValgrindError(void)
347 {
348  uint8_t buffer[] = {
349  0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2C,
350  0x01,0x2C,0x00,0x00,0xFF,0xFE,0x00,0x4C,0x53,0x69,0x67,0x6E,0x61,0x74,0x75,0x72,
351  0x65,0x3A,0x34,0x31,0x31,0x65,0x33,0x38,0x61,0x61,0x61,0x31,0x37,0x65,0x33,0x30,
352  0x66,0x30,0x32,0x38,0x62,0x61,0x30,0x31,0x36,0x32,0x36,0x37,0x66,0x66,0x30,0x31,
353  0x36,0x36,0x61,0x65,0x35,0x39,0x65,0x38,0x31,0x39,0x62,0x61,0x32,0x34,0x63,0x39,
354  0x62,0x31,0x33,0x37,0x33,0x62,0x31,0x61,0x35,0x61,0x38,0x65,0x64,0x63,0x36,0x30,
355  0x65,0x37,0xFF,0xE2,0x02,0x2C,0x49,0x43,0x43,0x5F,0x50,0x52,0x4F,0x46,0x49,0x4C,
356  0x45,0x00,0x01,0x01,0x00,0x00,0x02,0x1C,0x41,0x44,0x42,0x45,0x02,0x10,0x00,0x00,
357  0x6D,0x6E,0x74,0x72,0x52,0x47,0x42,0x20,0x58,0x59,0x5A,0x20,0x07,0xCF,0x00,0x05,
358  0x00,0x09,0x00,0x15,0x00,0x0B,0x00,0x21,0x61,0x63,0x73,0x70,0x41,0x50,0x50,0x4C,
359  0x00,0x00,0x00,0x00,0x6E,0x6F,0x6E,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
360  };
361  size_t buffer_len = sizeof(buffer);
362 
363  magic_t ctx = MagicInitContext();
364  FAIL_IF(ctx == NULL);
365 
366  char *result = MagicThreadLookup(&ctx, buffer, buffer_len);
367  FAIL_IF_NULL(result);
368  FAIL_IF(strncmp(result, "JPEG", 4) != 0);
369  SCFree(result);
370 
371  MagicDeinitContext(ctx);
372  PASS;
373 }
374 
375 #endif /* UNITTESTS */
376 #endif
377 
379 {
380 #ifdef HAVE_MAGIC
381 #ifdef UNITTESTS
382  UtRegisterTest("MagicInitTest01", MagicInitTest01);
383  UtRegisterTest("MagicDetectTest01", MagicDetectTest01);
384  UtRegisterTest("MagicDetectTest03", MagicDetectTest03);
385  UtRegisterTest("MagicDetectTest04", MagicDetectTest04);
386  UtRegisterTest("MagicDetectTest05", MagicDetectTest05);
387  UtRegisterTest("MagicDetectTest07", MagicDetectTest07);
388  UtRegisterTest("MagicDetectTest08", MagicDetectTest08);
389  UtRegisterTest("MagicDetectTest10ValgrindError",
390  MagicDetectTest10ValgrindError);
391 #endif /* UNITTESTS */
392 #endif /* HAVE_MAGIC */
393 }
394 
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
MagicRegisterTests
void MagicRegisterTests(void)
Definition: util-magic.c:378
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:101
ctx
struct Thresholds ctx
SCConfGet
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:352
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:262
conf.h
util-magic.h
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:300
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
str
#define str(s)
Definition: suricata-common.h:313
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCFree
#define SCFree(p)
Definition: util-mem.h:61
MacSet_::buf
MacAddr * buf[2]
Definition: util-macset.c:54