[lttng-dev] [PATCH lttng-tools] Fix: scanf unbounded input
Mathieu Desnoyers
mathieu.desnoyers at efficios.com
Thu Feb 20 22:53:04 EST 2014
Awaiting a proper cleanup (introducing nscanf), do what we can to
validate the scanf input using its utterly broken API.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
---
src/bin/lttng/commands/enable_events.c | 13 ++++++++++---
src/bin/lttng/conf.c | 7 ++++++-
src/lib/lttng-ctl/filter/filter-parser.y | 31 ++++++++++++++++++++++--------
3 files changed, 39 insertions(+), 12 deletions(-)
diff --git a/src/bin/lttng/commands/enable_events.c b/src/bin/lttng/commands/enable_events.c
index 29a399e..bd2d997 100644
--- a/src/bin/lttng/commands/enable_events.c
+++ b/src/bin/lttng/commands/enable_events.c
@@ -30,6 +30,10 @@
#include "../command.h"
#include <src/common/sessiond-comm/sessiond-comm.h>
+#if (LTTNG_SYMBOL_NAME_LEN == 256)
+#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
+#endif
+
static char *opt_event_list;
static int opt_event_type;
static const char *opt_loglevel;
@@ -226,6 +230,7 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt)
{
int ret;
char s_hex[19];
+#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18" /* 18 is (19 - 1) (\0 is extra) */
char name[LTTNG_SYMBOL_NAME_LEN];
if (opt == NULL) {
@@ -234,7 +239,8 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt)
}
/* Check for symbol+offset */
- ret = sscanf(opt, "%[^'+']+%s", name, s_hex);
+ ret = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
+ "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", name, s_hex);
if (ret == 2) {
strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
@@ -252,7 +258,8 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt)
/* Check for symbol */
if (isalpha(name[0])) {
- ret = sscanf(opt, "%s", name);
+ ret = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s",
+ name);
if (ret == 1) {
strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
@@ -265,7 +272,7 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt)
}
/* Check for address */
- ret = sscanf(opt, "%s", s_hex);
+ ret = sscanf(opt, "%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", s_hex);
if (ret > 0) {
if (*s_hex == '\0') {
ERR("Invalid probe address %s", s_hex);
diff --git a/src/bin/lttng/conf.c b/src/bin/lttng/conf.c
index 5a0da9d..55ed635 100644
--- a/src/bin/lttng/conf.c
+++ b/src/bin/lttng/conf.c
@@ -186,6 +186,9 @@ char *config_read_session_name(char *path)
int ret;
FILE *fp;
char var[NAME_MAX], *session_name;
+#if (NAME_MAX == 255)
+#define NAME_MAX_SCANF_IS_A_BROKEN_API "254"
+#endif
session_name = malloc(NAME_MAX);
if (session_name == NULL) {
@@ -202,7 +205,9 @@ char *config_read_session_name(char *path)
}
while (!feof(fp)) {
- if ((ret = fscanf(fp, "%[^'=']=%s\n", var, session_name)) != 2) {
+ if ((ret = fscanf(fp, "%" NAME_MAX_SCANF_IS_A_BROKEN_API
+ "[^'=']=%" NAME_MAX_SCANF_IS_A_BROKEN_API "s\n",
+ var, session_name)) != 2) {
if (ret == -1) {
ERR("Missing session=NAME in config file.");
goto error_close;
diff --git a/src/lib/lttng-ctl/filter/filter-parser.y b/src/lib/lttng-ctl/filter/filter-parser.y
index 29e2866..d746f78 100644
--- a/src/lib/lttng-ctl/filter/filter-parser.y
+++ b/src/lib/lttng-ctl/filter/filter-parser.y
@@ -34,6 +34,11 @@
#include <common/macros.h>
+#define WIDTH_u64_SCANF_IS_A_BROKEN_API "20"
+#define WIDTH_o64_SCANF_IS_A_BROKEN_API "22"
+#define WIDTH_x64_SCANF_IS_A_BROKEN_API "17"
+#define WIDTH_lg_SCANF_IS_A_BROKEN_API "4096" /* Hugely optimistic approximation */
+
LTTNG_HIDDEN
int yydebug;
LTTNG_HIDDEN
@@ -399,29 +404,39 @@ primary_expression
{
$$ = make_node(parser_ctx, NODE_EXPRESSION);
$$->u.expression.type = AST_EXP_CONSTANT;
- sscanf(yylval.gs->s, "%" PRIu64,
- &$$->u.expression.u.constant);
+ if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64,
+ &$$->u.expression.u.constant) != 1) {
+ parse_error(parser_ctx, "cannot scanf decimal constant");
+ }
}
| OCTAL_CONSTANT
{
$$ = make_node(parser_ctx, NODE_EXPRESSION);
$$->u.expression.type = AST_EXP_CONSTANT;
- sscanf(yylval.gs->s, "0%" PRIo64,
- &$$->u.expression.u.constant);
+ if (!strcmp(yylval.gs->s, "0")) {
+ $$->u.expression.u.constant = 0;
+ } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64,
+ &$$->u.expression.u.constant) != 1) {
+ parse_error(parser_ctx, "cannot scanf octal constant");
+ }
}
| HEXADECIMAL_CONSTANT
{
$$ = make_node(parser_ctx, NODE_EXPRESSION);
$$->u.expression.type = AST_EXP_CONSTANT;
- sscanf(yylval.gs->s, "0x%" PRIx64,
- &$$->u.expression.u.constant);
+ if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64,
+ &$$->u.expression.u.constant) != 1) {
+ parse_error(parser_ctx, "cannot scanf hexadecimal constant");
+ }
}
| FLOAT_CONSTANT
{
$$ = make_node(parser_ctx, NODE_EXPRESSION);
$$->u.expression.type = AST_EXP_FLOAT_CONSTANT;
- sscanf(yylval.gs->s, "%lg",
- &$$->u.expression.u.float_constant);
+ if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg",
+ &$$->u.expression.u.float_constant) != 1) {
+ parse_error(parser_ctx, "cannot scanf float constant");
+ }
}
| STRING_LITERAL_START DQUOTE
{
--
1.7.10.4
More information about the lttng-dev
mailing list