Skip to content

Commit 92877db

Browse files
committed
* fixing memory management issues in callbacks
* adding a callback to allow external code to free the memory used to return the include callback's result * API: un-exposing yara's memory management functions * making include callbacks the only way ton include files * adding a default include callback to open files from the disk (mimicking original behavior) * updating docs accordingly
1 parent e98f434 commit 92877db

File tree

7 files changed

+273
-425
lines changed

7 files changed

+273
-425
lines changed

docs/capi.rst

+20-32
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ The callback receives the following parameters:
7272
* ``include_name``: name of the requested file.
7373
* ``calling_rule_filename``: the requesting file name (NULL if not a file).
7474
* ``calling_rule_namespace``: namespace (NULL if undefined).
75-
* ``user_data`` pointer is the same you passed to
76-
:c:func:`yr_compiler_set_include_callback`.
77-
It should return the requested file's content as a string. The memory for this string
78-
should be allocated by the callback function (yr_malloc can be used) but will
79-
be automatically freed by the yara compiler.
75+
* ``user_data`` pointer is the same you passed to :c:func:`yr_compiler_set_include_callback`.
76+
It should return the requested file's content as a string. The memory for this
77+
string should be allocated by the callback function. Once it is safe to free the
78+
memory used to return the callback's result, the include_free function passed to
79+
:c:func:`yr_compiler_set_include_callback` will be called. If the memory does
80+
not need to be freed, NULL can be passed as include_free instead.
8081

8182
The callback function has the following prototype:
8283

@@ -88,6 +89,14 @@ The callback function has the following prototype:
8889
const char* calling_rule_namespace,
8990
void* user_data);
9091
92+
The free function has the following prototype:
93+
94+
.. code-block:: c
95+
96+
void include_free(
97+
const char* callback_result_ptr,
98+
void* user_data);
99+
91100
After you successfully added some sources you can get the compiled rules
92101
using the :c:func:`yr_compiler_get_rules()` function. You'll get a pointer to
93102
a :c:type:`YR_RULES` structure which can be used to scan your data as
@@ -427,10 +436,13 @@ Functions
427436
pointer is passed to the callback function.
428437
429438
430-
.. c:function:: void yr_compiler_set_include_callback(YR_COMPILER* compiler, YR_COMPILER_INCLUDE_CALLBACK_FUNC callback, void* user_data)
439+
.. c:function:: void yr_compiler_set_include_callback(YR_COMPILER* compiler, YR_COMPILER_INCLUDE_CALLBACK_FUNC callback, YR_COMPILER_INCLUDE_FREE_FUNC include_free, void* user_data)
431440
432-
Set a callback to provide rules from a custom source when ``include`` directive
433-
is invoked. The *user_data* pointer is passed to the callback function.
441+
Set a callback to provide rules from a custom source when ``include``
442+
directive is invoked. The *user_data* pointer is untouched and passed back to
443+
the callback function and to the free function. Once the callback's result
444+
is no longer needed, the include_free function will be called. If the memory
445+
does not need to be freed, include_free can be set to NULL.
434446
435447
436448
.. c:function:: int yr_compiler_add_file(YR_COMPILER* compiler, FILE* file, const char* namespace, const char* file_name)
@@ -699,30 +711,6 @@ Functions
699711
Enables the specified rule. After being disabled with :c:func:`yr_rule_disable`
700712
a rule can be enabled again by using this function.
701713

702-
.. c:function:: void* yr_calloc(size_t count, size_t size);
703-
704-
Cross-platform wrapper for HeapAlloc on Windows and calloc on other platforms.
705-
706-
.. c:function:: void* yr_malloc(size_t size);
707-
708-
Cross-platform wrapper for HeapAlloc on Windows and malloc on other platforms.
709-
710-
.. c:function:: void* yr_realloc(void* ptr, size_t size);
711-
712-
Cross-platform wrapper for HeapReAlloc on Windows and realloc on other platforms.
713-
714-
.. c:function:: void yr_free(void* ptr);
715-
716-
Cross-platform wrapper for HeapFree on Windows and free on other platforms.
717-
718-
.. c:function:: char* yr_strdup(const char *str);
719-
720-
Allocates a new buffer the same size as str and copies str to the new buffer.
721-
722-
.. c:function:: char* yr_strdup(const char *str, size_t n);
723-
724-
Allocates a new buffer of size n and copies the n first character of str.
725-
726714

727715
Error codes
728716
-----------

libyara/compiler.c

+97-29
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ YR_API int yr_compiler_create(
5656

5757
new_compiler->errors = 0;
5858
new_compiler->callback = NULL;
59-
new_compiler->include_callback = NULL;
59+
new_compiler->include_callback = _yr_compiler_default_include_callback;
60+
new_compiler->include_free = _yr_compiler_default_include_free;
6061
new_compiler->last_error = ERROR_SUCCESS;
6162
new_compiler->last_error_line = 0;
6263
new_compiler->current_line = 0;
6364
new_compiler->last_result = ERROR_SUCCESS;
64-
new_compiler->file_stack_ptr = 0;
6565
new_compiler->file_name_stack_ptr = 0;
6666
new_compiler->fixup_stack_head = NULL;
6767
new_compiler->allow_includes = 1;
@@ -183,48 +183,116 @@ YR_API void yr_compiler_set_callback(
183183
}
184184

185185

186-
YR_API void yr_compiler_set_include_callback(
187-
YR_COMPILER* compiler,
188-
YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback,
189-
void* user_data)
186+
const char* _yr_compiler_default_include_callback(
187+
const char* include_name,
188+
const char* calling_rule_filename,
189+
const char* calling_rule_namespace,
190+
void* user_data)
190191
{
191-
compiler->include_callback = include_callback;
192-
compiler->incl_clbk_user_data = user_data;
193-
}
194-
195-
196-
int _yr_compiler_push_file(
197-
YR_COMPILER* compiler,
198-
FILE* fh)
199-
{
200-
if (compiler->file_stack_ptr < MAX_INCLUDE_DEPTH)
192+
char* buffer;
193+
//char buffer[1024];
194+
char* s = NULL;
195+
#ifdef _WIN32
196+
char* b = NULL;
197+
#endif
198+
char* f;
199+
FILE* fh;
200+
char* file_buffer;
201+
size_t file_length;
202+
203+
if(calling_rule_filename != NULL)
201204
{
202-
compiler->file_stack[compiler->file_stack_ptr] = fh;
203-
compiler->file_stack_ptr++;
204-
return ERROR_SUCCESS;
205+
buffer = (char*) calling_rule_filename;
206+
//strlcpy(buffer, calling_rule_filename, sizeof(buffer));
205207
}
206208
else
207209
{
208-
compiler->last_result = ERROR_INCLUDE_DEPTH_EXCEEDED;
209-
return ERROR_INCLUDE_DEPTH_EXCEEDED;
210+
buffer = "\0";
211+
//buffer[0] = '\0';
212+
}
213+
// make included file path relative to current source file
214+
s = strrchr(buffer, '/');
215+
216+
#ifdef _WIN32
217+
b = strrchr(buffer, '\\'); // in Windows both path delimiters are accepted
218+
#endif
219+
#ifdef _WIN32
220+
if (s != NULL || b != NULL)
221+
#else
222+
if (s != NULL)
223+
#endif
224+
{
225+
#ifdef _WIN32
226+
f = (b > s)? (b + 1): (s + 1);
227+
#else
228+
f = s + 1;
229+
#endif
230+
strlcpy(f, include_name, sizeof(buffer) - (f - buffer));
231+
f = buffer;
232+
// SECURITY: Potential for directory traversal here.
233+
fh = fopen(buffer, "r");
234+
// if include file was not found relative to current source file,
235+
// try to open it with path as specified by user (maybe user wrote
236+
// a full path)
237+
if (fh == NULL)
238+
{
239+
f = (char*) include_name;
240+
// SECURITY: Potential for directory traversal here.
241+
fh = fopen(include_name, "r");
242+
}
243+
}
244+
else
245+
{
246+
f = (char*) include_name;
247+
// SECURITY: Potential for directory traversal here.
248+
fh = fopen(include_name, "r");
249+
}
250+
if (fh != NULL)
251+
{
252+
file_buffer = NULL;
253+
file_length = 0;
254+
255+
fseek(fh, 0, SEEK_END);
256+
file_length = ftell(fh);
257+
fseek(fh, 0, SEEK_SET);
258+
file_buffer = (char*) yr_malloc((file_length+1)*sizeof(char));
259+
if(file_buffer)
260+
{
261+
if(file_length != fread(file_buffer, sizeof(char), file_length, fh))
262+
{
263+
return NULL;
264+
}
265+
}
266+
fclose(fh);
267+
return file_buffer;
210268
}
269+
else return NULL;
211270
}
212271

213272

214-
FILE* _yr_compiler_pop_file(
215-
YR_COMPILER* compiler)
273+
void _yr_compiler_default_include_free(
274+
const char* callback_result_ptr,
275+
void* user_data)
216276
{
217-
FILE* result = NULL;
218-
219-
if (compiler->file_stack_ptr > 0)
277+
if(callback_result_ptr != NULL)
220278
{
221-
compiler->file_stack_ptr--;
222-
result = compiler->file_stack[compiler->file_stack_ptr];
279+
yr_free((void*)callback_result_ptr);
223280
}
281+
}
224282

225-
return result;
283+
284+
YR_API void yr_compiler_set_include_callback(
285+
YR_COMPILER* compiler,
286+
YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback,
287+
YR_COMPILER_INCLUDE_FREE_FUNC include_free,
288+
void* user_data)
289+
{
290+
compiler->include_callback = include_callback;
291+
compiler->include_free = include_free;
292+
compiler->incl_clbk_user_data = user_data;
226293
}
227294

295+
228296
int _yr_compiler_push_file_name(
229297
YR_COMPILER* compiler,
230298
const char* file_name)

libyara/include/yara/compiler.h

+16-11
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ typedef const char* (*YR_COMPILER_INCLUDE_CALLBACK_FUNC)(
5858
const char* calling_rule_namespace,
5959
void* user_data);
6060

61+
typedef void (*YR_COMPILER_INCLUDE_FREE_FUNC)(
62+
const char* callback_result_ptr,
63+
void* user_data );
64+
6165

6266
typedef struct _YR_FIXUP
6367
{
@@ -110,9 +114,6 @@ typedef struct _YR_COMPILER
110114
char* file_name_stack[MAX_INCLUDE_DEPTH];
111115
int file_name_stack_ptr;
112116

113-
FILE* file_stack[MAX_INCLUDE_DEPTH];
114-
int file_stack_ptr;
115-
116117
char last_error_extra_info[MAX_COMPILER_ERROR_EXTRA_INFO];
117118

118119
char lex_buf[LEX_BUF_SIZE];
@@ -125,6 +126,8 @@ typedef struct _YR_COMPILER
125126

126127
YR_COMPILER_CALLBACK_FUNC callback;
127128
YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback;
129+
YR_COMPILER_INCLUDE_FREE_FUNC include_free;
130+
128131

129132
} YR_COMPILER;
130133

@@ -143,14 +146,6 @@ typedef struct _YR_COMPILER
143146
fmt, __VA_ARGS__);
144147

145148

146-
int _yr_compiler_push_file(
147-
YR_COMPILER* compiler,
148-
FILE* fh);
149-
150-
151-
FILE* _yr_compiler_pop_file(
152-
YR_COMPILER* compiler);
153-
154149

155150
int _yr_compiler_push_file_name(
156151
YR_COMPILER* compiler,
@@ -160,6 +155,15 @@ int _yr_compiler_push_file_name(
160155
void _yr_compiler_pop_file_name(
161156
YR_COMPILER* compiler);
162157

158+
const char* _yr_compiler_default_include_callback(
159+
const char* include_name,
160+
const char* calling_rule_filename,
161+
const char* calling_rule_namespace,
162+
void* user_data);
163+
164+
void _yr_compiler_default_include_free(
165+
const char* callback_result_ptr,
166+
void* user_data);
163167

164168
YR_API int yr_compiler_create(
165169
YR_COMPILER** compiler);
@@ -178,6 +182,7 @@ YR_API void yr_compiler_set_callback(
178182
YR_API void yr_compiler_set_include_callback(
179183
YR_COMPILER* compiler,
180184
YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback,
185+
YR_COMPILER_INCLUDE_FREE_FUNC include_free,
181186
void* user_data);
182187

183188

libyara/include/yara/mem.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4646

4747
#else
4848

49-
YR_API void* yr_calloc(
49+
void* yr_calloc(
5050
size_t count,
5151
size_t size);
5252

53-
YR_API void* yr_malloc(
53+
void* yr_malloc(
5454
size_t size);
5555

56-
YR_API void* yr_realloc(
56+
void* yr_realloc(
5757
void* ptr,
5858
size_t size);
5959

60-
YR_API void yr_free(
60+
void yr_free(
6161
void *ptr);
6262

63-
YR_API char* yr_strdup(
63+
char* yr_strdup(
6464
const char *str);
6565

66-
YR_API char* yr_strndup(
66+
char* yr_strndup(
6767
const char *str, size_t n);
6868

6969
#endif

0 commit comments

Comments
 (0)