cf8b18d7 |
#include <string.h>
#include <setjmp.h>
#ifdef REAL_YARA
#include <yara/lexer.h>
#include <yara/rules.h>
#include <yara/sizedstr.h>
#include <yara/error.h>
#include <yara/mem.h>
#include <yara/utils.h>
#include "grammar.h"
#else
#include "others.h"
#include "yara_clam.h"
#include "yara_grammar.h"
#include "yara_lexer.h"
#endif
#define LEX_CHECK_SPACE_OK(data, current_size, max_length) \
if (strlen(data) + current_size >= max_length - 1) \
{ \
yyerror(yyscanner, compiler, "out of space in lex_buf"); \
yyterminate(); \
}
#define YYTEXT_TO_BUFFER \
{ \
char *yptr = yytext; \
LEX_CHECK_SPACE_OK(yptr, yyextra->lex_buf_len, LEX_BUF_SIZE); \
while(*yptr) \
{ \
*yyextra->lex_buf_ptr++ = *yptr++; \
yyextra->lex_buf_len++; \
} \
}
#ifdef _WIN32
#define snprintf _snprintf
#endif
%}
%option reentrant bison-bridge
%option noyywrap
%option nounistd
%option noinput
%option nounput
%option yylineno
%option prefix="yara_yy"
%option outfile="lex.yy.c"
%option verbose
%option warn
%x str
%x regexp
%x include
%x comment
digit [0-9]
letter [a-zA-Z]
hexdigit [a-fA-F0-9]
%%
"<" { return _LT_; }
">" { return _GT_; }
"<=" { return _LE_; }
">=" { return _GE_; }
"==" { return _EQ_; }
"!=" { return _NEQ_; }
"<<" { return _SHIFT_LEFT_; }
">>" { return _SHIFT_RIGHT_; }
"private" { return _PRIVATE_; }
"global" { return _GLOBAL_; }
"rule" { return _RULE_; }
"meta" { return _META_; }
"strings" { return _STRINGS_; }
"ascii" { return _ASCII_; }
"wide" { return _WIDE_; }
"fullword" { return _FULLWORD_; }
"nocase" { return _NOCASE_; }
"condition" { return _CONDITION_; }
"true" { return _TRUE_; }
"false" { return _FALSE_; }
"not" { return _NOT_; }
"and" { return _AND_; }
"or" { return _OR_; }
"at" { return _AT_; }
"in" { return _IN_; }
"of" { return _OF_; }
"them" { return _THEM_; }
"for" { return _FOR_; }
"all" { return _ALL_; }
"any" { return _ANY_; }
"entrypoint" { return _ENTRYPOINT_; }
"filesize" { return _FILESIZE_; }
"uint8" { return _UINT8_; }
"uint16" { return _UINT16_; }
"uint32" { return _UINT32_; }
"int8" { return _INT8_; }
"int16" { return _INT16_; }
"int32" { return _INT32_; }
"matches" { return _MATCHES_; }
"contains" { return _CONTAINS_; }
"import" { return _IMPORT_; }
"/*" { BEGIN(comment); }
<comment>"*/" { BEGIN(INITIAL); }
<comment>(.|\n) { /* skip comments */ }
"//"[^\n]* { /* skip single-line comments */ }
include[ \t]+\" {
yyextra->lex_buf_ptr = yyextra->lex_buf;
yyextra->lex_buf_len = 0;
BEGIN(include);
}
<include>[^\"]+ { YYTEXT_TO_BUFFER; }
<include>\" {
char buffer[1024];
char *current_file_name;
char *s = NULL;
char *b = NULL;
char *f;
FILE* fh;
if (compiler->allow_includes)
{
*yyextra->lex_buf_ptr = '\0'; // null-terminate included file path
// move path of current source file into buffer
current_file_name = yr_compiler_get_current_file_name(compiler);
if (current_file_name != NULL)
{
strlcpy(buffer, current_file_name, sizeof(buffer));
}
else
{
buffer[0] = '\0';
}
// make included file path relative to current source file
s = strrchr(buffer, '/');
#ifdef _WIN32
b = strrchr(buffer, '\\'); // in Windows both path delimiters are accepted
#endif
if (s != NULL || b != NULL)
{
f = (b > s)? (b + 1): (s + 1);
strlcpy(f, yyextra->lex_buf, sizeof(buffer) - (f - buffer));
f = buffer;
// SECURITY: Potential for directory traversal here.
fh = fopen(buffer, "r");
// if include file was not found relative to current source file,
// try to open it with path as specified by user (maybe user wrote
// a full path)
if (fh == NULL)
{
f = yyextra->lex_buf;
// SECURITY: Potential for directory traversal here.
fh = fopen(yyextra->lex_buf, "r");
}
}
else
{
f = yyextra->lex_buf;
// SECURITY: Potential for directory traversal here.
fh = fopen(yyextra->lex_buf, "r");
}
if (fh != NULL)
{
int error_code = _yr_compiler_push_file_name(compiler, f);
if (error_code != ERROR_SUCCESS)
{
if (error_code == ERROR_INCLUDES_CIRCULAR_REFERENCE)
{
yyerror(yyscanner, compiler, "includes circular reference");
}
else if (error_code == ERROR_INCLUDE_DEPTH_EXCEEDED)
{
yyerror(yyscanner, compiler, "includes depth exceeded");
}
yyterminate();
}
_yr_compiler_push_file(compiler, fh);
yypush_buffer_state(
yy_create_buffer(fh, YY_BUF_SIZE, yyscanner), yyscanner);
}
else
{
snprintf(buffer, sizeof(buffer),
"can't open include file: %s", yyextra->lex_buf);
yyerror(yyscanner, compiler, buffer);
}
}
else // not allowing includes
{
yyerror(yyscanner, compiler, "includes are disabled");
yyterminate();
}
BEGIN(INITIAL);
}
<<EOF>> {
YR_COMPILER* compiler = yyget_extra(yyscanner);
FILE* file = _yr_compiler_pop_file(compiler);
if (file != NULL)
{
fclose(file);
}
_yr_compiler_pop_file_name(compiler);
yypop_buffer_state(yyscanner);
if (!YY_CURRENT_BUFFER)
{
yyterminate();
}
}
$({letter}|{digit}|_)*"*" {
yylval->c_string = yr_strdup(yytext);
if (yylval->c_string == NULL)
{
yyerror(yyscanner, compiler, "not enough memory");
yyterminate();
}
return _STRING_IDENTIFIER_WITH_WILDCARD_;
}
$({letter}|{digit}|_)* {
yylval->c_string = yr_strdup(yytext);
if (yylval->c_string == NULL)
{
yyerror(yyscanner, compiler, "not enough memory");
yyterminate();
}
return _STRING_IDENTIFIER_;
}
#({letter}|{digit}|_)* {
yylval->c_string = yr_strdup(yytext);
if (yylval->c_string == NULL)
{
yyerror(yyscanner, compiler, "not enough memory");
yyterminate();
}
yylval->c_string[0] = '$'; /* replace # by $*/
return _STRING_COUNT_;
}
@({letter}|{digit}|_)* {
yylval->c_string = yr_strdup(yytext);
if (yylval->c_string == NULL)
{
yyerror(yyscanner, compiler, "not enough memory");
yyterminate();
}
yylval->c_string[0] = '$'; /* replace @ by $*/
return _STRING_OFFSET_;
}
({letter}|_)({letter}|{digit}|_)* {
if (strlen(yytext) > 128)
{
yyerror(yyscanner, compiler, "indentifier too long");
}
yylval->c_string = yr_strdup(yytext);
if (yylval->c_string == NULL)
{
yyerror(yyscanner, compiler, "not enough memory");
yyterminate();
}
return _IDENTIFIER_;
}
{digit}+(MB|KB){0,1} {
yylval->integer = (size_t) atol(yytext);
if (strstr(yytext, "KB") != NULL)
{
yylval->integer *= 1024;
}
else if (strstr(yytext, "MB") != NULL)
{
yylval->integer *= 1048576;
}
return _NUMBER_;
}
0x{hexdigit}+ {
yylval->integer = xtoi(yytext + 2);
return _NUMBER_;
}
<str>\" { /* saw closing quote - all done */
SIZED_STRING* s;
if (yyextra->lex_buf_len == 0)
{
yyerror(yyscanner, compiler, "empty string");
}
*yyextra->lex_buf_ptr = '\0';
BEGIN(INITIAL);
s = (SIZED_STRING*) yr_malloc(yyextra->lex_buf_len + sizeof(SIZED_STRING));
s->length = yyextra->lex_buf_len;
s->flags = 0;
memcpy(s->c_string, yyextra->lex_buf, yyextra->lex_buf_len + 1);
yylval->sized_string = s;
return _TEXT_STRING_;
}
<str>\\t {
LEX_CHECK_SPACE_OK("\t", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = '\t';
yyextra->lex_buf_len++;
}
<str>\\n {
LEX_CHECK_SPACE_OK("\n", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = '\n';
yyextra->lex_buf_len++;
}
<str>\\\" {
LEX_CHECK_SPACE_OK("\"", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = '\"';
yyextra->lex_buf_len++;
}
<str>\\\\ {
LEX_CHECK_SPACE_OK("\\", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = '\\';
yyextra->lex_buf_len++;
}
<str>\\x{hexdigit}{2} {
int result;
sscanf( yytext + 2, "%x", &result );
LEX_CHECK_SPACE_OK("X", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = result;
yyextra->lex_buf_len++;
}
<str>[^\\\n\"]+ { YYTEXT_TO_BUFFER; }
<str>\n {
yyerror(yyscanner, compiler, "unterminated string");
yyterminate();
}
<str>\\(.|\n) {
yyerror(yyscanner, compiler, "illegal escape sequence");
}
<regexp>\/i?s? {
SIZED_STRING* s;
if (yyextra->lex_buf_len == 0)
{
yyerror(yyscanner, compiler, "empty regular expression");
}
*yyextra->lex_buf_ptr = '\0';
BEGIN(INITIAL);
s = (SIZED_STRING*) yr_malloc(yyextra->lex_buf_len + sizeof(SIZED_STRING));
s->flags = 0;
if (yytext[1] == 'i')
s->flags |= SIZED_STRING_FLAGS_NO_CASE;
if (yytext[1] == 's' || yytext[2] == 's')
s->flags |= SIZED_STRING_FLAGS_DOT_ALL;
s->length = yyextra->lex_buf_len;
strlcpy(s->c_string, yyextra->lex_buf, s->length + 1);
yylval->sized_string = s;
return _REGEXP_;
}
<regexp>\\\/ {
LEX_CHECK_SPACE_OK("/", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = '/';
yyextra->lex_buf_len++ ;
}
<regexp>\\. {
LEX_CHECK_SPACE_OK("\\.", yyextra->lex_buf_len, LEX_BUF_SIZE);
*yyextra->lex_buf_ptr++ = yytext[0];
*yyextra->lex_buf_ptr++ = yytext[1];
yyextra->lex_buf_len += 2;
}
<regexp>[^/\n\\]+ { YYTEXT_TO_BUFFER; }
<regexp>\n {
yyerror(yyscanner, compiler, "unterminated regular expression");
yyterminate();
}
\" {
yyextra->lex_buf_ptr = yyextra->lex_buf;
yyextra->lex_buf_len = 0;
BEGIN(str);
}
"/" {
yyextra->lex_buf_ptr = yyextra->lex_buf;
yyextra->lex_buf_len = 0;
BEGIN(regexp);
}
\{({hexdigit}|[ \-|\?\[\]\(\)\n\t])+\} {
int len = strlen(yytext);
SIZED_STRING* s = (SIZED_STRING*) yr_malloc(len + sizeof(SIZED_STRING));
s->length = len;
s->flags = 0;
strlcpy(s->c_string, yytext, s->length + 1);
yylval->sized_string = s;
return _HEX_STRING_;
}
[ \t\r\n] /* skip whitespace */
. {
if (yytext[0] >= 32 && yytext[0] < 127)
{
return yytext[0];
}
else
{
yyerror(yyscanner, compiler, "non-ascii character");
yyterminate();
}
}
%%
void yywarning(
yyscan_t yyscanner,
const char *warning_message)
{
YR_COMPILER* compiler = yyget_extra(yyscanner);
char* file_name;
if (compiler->file_name_stack_ptr > 0)
file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1];
else
file_name = NULL;
|