Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/flexdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,10 @@ extern void dataflush(void);
/* Report an error message and terminate. */
extern void flexerror(const char *);

/* Reject `[` / `]` in a %option= value to prevent m4-quote injection. */
extern void reject_brackets_in_option_value(const char *opt_name,
const char *val);

/* Report a fatal error message and terminate. */
extern void flexfatal(const char *);

Expand Down
24 changes: 24 additions & 0 deletions src/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,30 @@ void flexerror (const char *msg)
}


/* reject_brackets_in_option_value - bail out if a %option= value contains
* `[` or `]`. Such characters break out of the m4 quoting scheme that
* flex uses to interpolate option values into m4 input (see PR #81 which
* added the same escaping for action / code-block contexts via
* ESCAPED_QSTART / ESCAPED_QEND in src/scan.l). The OPTION-state
* quoted-string rule at src/scan.l:480 was never plumbed through that
* escape, so without this guard a malicious .l file can inject arbitrary
* m4 (e.g. m4_syscmd) into the output pipeline.
*
* Mirrors the existing prefix= guard that has been in parse.y since
* before PR #81.
*/
void reject_brackets_in_option_value (const char *opt_name, const char *val)
{
if (val != NULL && (strchr (val, '[') || strchr (val, ']'))) {
char msg[MAXLINE];
snprintf (msg, sizeof msg,
_("%%option %s value must not contain '[' or ']'"),
opt_name);
flexerror (msg);
}
}


/* flexfatal - report a fatal error message and terminate */

void flexfatal (const char *msg)
Expand Down
27 changes: 17 additions & 10 deletions src/parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -199,35 +199,42 @@ optionlist : optionlist option

option : TOK_OUTFILE '=' NAME
{
reject_brackets_in_option_value("outfile", nmstr);
env.outfilename = xstrdup(nmstr);
env.did_outfilename = 1;
}
| TOK_EXTRA_TYPE '=' NAME
{ extra_type = xstrdup(nmstr); }
{ reject_brackets_in_option_value("extra-type", nmstr);
extra_type = xstrdup(nmstr); }
| TOK_PREFIX '=' NAME
{ ctrl.prefix = xstrdup(nmstr);
if (strchr(ctrl.prefix, '[') || strchr(ctrl.prefix, ']'))
flexerror(_("Prefix must not contain [ or ]")); }
{ reject_brackets_in_option_value("prefix", nmstr);
ctrl.prefix = xstrdup(nmstr); }
| TOK_YYCLASS '=' NAME
{ ctrl.yyclass = xstrdup(nmstr); }
{ reject_brackets_in_option_value("yyclass", nmstr);
ctrl.yyclass = xstrdup(nmstr); }
| TOK_HEADER_FILE '=' NAME
{ env.headerfilename = xstrdup(nmstr); }
{ reject_brackets_in_option_value("header-file", nmstr);
env.headerfilename = xstrdup(nmstr); }
| TOK_YYLMAX '=' TOK_NUMERIC
{ ctrl.yylmax = nmval; }
| TOK_YYDECL '=' NAME
{ ctrl.yydecl = xstrdup(nmstr); }
{ reject_brackets_in_option_value("yydecl", nmstr);
ctrl.yydecl = xstrdup(nmstr); }
| TOK_PREACTION '=' NAME
{ ctrl.preaction = xstrdup(nmstr); }
{ reject_brackets_in_option_value("pre-action", nmstr);
ctrl.preaction = xstrdup(nmstr); }
| TOK_POSTACTION '=' NAME
{ ctrl.postaction = xstrdup(nmstr); }
{ reject_brackets_in_option_value("post-action", nmstr);
ctrl.postaction = xstrdup(nmstr); }
| TOK_BUFSIZE '=' TOK_NUMERIC
{ ctrl.bufsize = nmval; }
| TOK_EMIT '=' NAME
{ ctrl.emit = xstrdup(nmstr); backend_by_name(ctrl.emit); }
| TOK_USERINIT '=' NAME
{ ctrl.userinit = xstrdup(nmstr); }
| TOK_YYTERMINATE '=' NAME
{ ctrl.yyterminate = xstrdup(nmstr); }
{ reject_brackets_in_option_value("yyterminate", nmstr);
ctrl.yyterminate = xstrdup(nmstr); }
| TOK_TABLES_FILE '=' NAME
{ tablesext = true; tablesfilename = xstrdup(nmstr); }
;
Expand Down