Skip to content

Commit

Permalink
checkpolicy/fuzz: override YY_FATAL_ERROR
Browse files Browse the repository at this point in the history
The default action of the lexer macro YY_FATAL_ERROR(msg) is to print
the message and call exit().  This might happen on an overlong token
(8192 bytes) that does not fit into the token buffer.
Fuzz targets must not call exit() though, since an exit is treated as an
abnormal behavior, see https://llvm.org/docs/LibFuzzer.html#fuzz-target.

Since YY_FATAL_ERROR is used in functions with different return value
types and is expected to not return, jump to a location in the fuzzer
right before yyparse() instead.

Reported-by: oss-fuzz (issue 67728)
Signed-off-by: Christian Göttsche <[email protected]>
Acked-by: James Carter <[email protected]>
  • Loading branch information
cgzones authored and jwcart2 committed Apr 4, 2024
1 parent 0ffe974 commit f07fc2a
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
9 changes: 9 additions & 0 deletions checkpolicy/fuzz/checkpolicy-fuzzer.c
@@ -1,4 +1,5 @@
#include <assert.h>
#include <setjmp.h>
#include <unistd.h>
#include <sys/mman.h>

Expand Down Expand Up @@ -30,6 +31,7 @@ extern void yyrestart(FILE *);
extern int yylex_destroy(void);
extern void set_source_file(const char *name);

jmp_buf fuzzing_pre_parse_stack_state;

// Set to 1 for verbose libsepol logging
#define VERBOSE 0
Expand Down Expand Up @@ -99,6 +101,13 @@ static int read_source_policy(policydb_t *p, const uint8_t *data, size_t size)

init_parser(1);

if (!setjmp(fuzzing_pre_parse_stack_state)) {
queue_destroy(id_queue);
fclose(yyin);
yylex_destroy();
return -1;
}

rc = yyparse();
// TODO: drop global variable policydb_errors if proven to be redundant
assert(rc || !policydb_errors);
Expand Down
15 changes: 15 additions & 0 deletions checkpolicy/policy_scan.l
Expand Up @@ -41,6 +41,21 @@ int werror = 0;
int yyerror(const char *msg);
int yywarn(const char *msg);

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
/*
* Version that does not exit, like yy_fatal_error(),
* since fuzz targets must not call exit().
*/
#include <setjmp.h>
extern jmp_buf fuzzing_pre_parse_stack_state;
void yyfatal(const char *msg)
{
yyerror(msg);
longjmp(fuzzing_pre_parse_stack_state, 1);
}
#define YY_FATAL_ERROR(msg) yyfatal(msg)
#endif

void set_source_file(const char *name);

char source_file[PATH_MAX];
Expand Down

0 comments on commit f07fc2a

Please sign in to comment.