diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-12-16 23:33:28 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-12-18 11:19:05 +0100 |
commit | e91fc2495b78808b363fb0324bdca14ac03cad18 (patch) | |
tree | 19705adbb8175aebbef7ef0d97f9a76a2d69e240 /src/netlink_delinearize.c | |
parent | 6b29a5bebb957387fe1aac8fcbfd431e6be237f0 (diff) |
netlink_delinearize: add previous statement to rule_pp_ctx
564b0e7c13f9 ("netlink_delinearize: postprocess expression before range
merge") crashes nft when the previous statement is removed via
payload_dependency_kill() as this pointer is not valid anymore.
Move the pointer to the previous statement to rule_pp_ctx and invalidate
it when required.
Reported-by: "Pablo M. Bermudo Garay" <pablombg@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Reported-by: "Pablo M. Bermudo Garay" <pablombg@gmail.com>
Diffstat (limited to 'src/netlink_delinearize.c')
-rw-r--r-- | src/netlink_delinearize.c | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 8cbabc34..f68fca09 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -944,6 +944,7 @@ struct rule_pp_ctx { enum proto_bases pbase; struct stmt *pdep; struct stmt *stmt; + struct stmt *prev; }; /* @@ -957,6 +958,8 @@ static void payload_dependency_kill(struct rule_pp_ctx *ctx, struct expr *expr) list_del(&ctx->pdep->list); stmt_free(ctx->pdep); ctx->pbase = PROTO_BASE_INVALID; + if (ctx->pdep == ctx->prev) + ctx->prev = NULL; ctx->pdep = NULL; } } @@ -1529,46 +1532,47 @@ static bool expr_may_merge_range(struct expr *expr, struct expr *prev, return false; } -static void expr_postprocess_range(struct rule_pp_ctx *ctx, struct stmt *prev, - enum ops op) +static void expr_postprocess_range(struct rule_pp_ctx *ctx, enum ops op) { struct stmt *nstmt, *stmt = ctx->stmt; struct expr *nexpr, *rel; - nexpr = range_expr_alloc(&prev->location, expr_clone(prev->expr->right), + nexpr = range_expr_alloc(&ctx->prev->location, + expr_clone(ctx->prev->expr->right), expr_clone(stmt->expr->right)); expr_set_type(nexpr, stmt->expr->right->dtype, stmt->expr->right->byteorder); - rel = relational_expr_alloc(&prev->location, op, + rel = relational_expr_alloc(&ctx->prev->location, op, expr_clone(stmt->expr->left), nexpr); nstmt = expr_stmt_alloc(&stmt->location, rel); list_add_tail(&nstmt->list, &stmt->list); - list_del(&prev->list); - stmt_free(prev); + list_del(&ctx->prev->list); + stmt_free(ctx->prev); list_del(&stmt->list); stmt_free(stmt); ctx->stmt = nstmt; } -static void stmt_expr_postprocess(struct rule_pp_ctx *ctx, struct stmt *prev) +static void stmt_expr_postprocess(struct rule_pp_ctx *ctx) { enum ops op; expr_postprocess(ctx, &ctx->stmt->expr); - if (prev && ctx->stmt && ctx->stmt->ops->type == prev->ops->type && - expr_may_merge_range(ctx->stmt->expr, prev->expr, &op)) - expr_postprocess_range(ctx, prev, op); + if (ctx->prev && ctx->stmt && + ctx->stmt->ops->type == ctx->prev->ops->type && + expr_may_merge_range(ctx->stmt->expr, ctx->prev->expr, &op)) + expr_postprocess_range(ctx, op); } static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *rule) { struct rule_pp_ctx rctx; - struct stmt *stmt, *next, *prev = NULL; + struct stmt *stmt, *next; memset(&rctx, 0, sizeof(rctx)); proto_ctx_init(&rctx.pctx, rule->handle.family); @@ -1578,7 +1582,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r switch (stmt->ops->type) { case STMT_EXPRESSION: - stmt_expr_postprocess(&rctx, prev); + stmt_expr_postprocess(&rctx); break; case STMT_PAYLOAD: expr_postprocess(&rctx, &stmt->payload.expr); @@ -1620,7 +1624,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r default: break; } - prev = rctx.stmt; + rctx.prev = rctx.stmt; } } |