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