From b8b8e7b6ae10d6a0ab9f3778705f1b075e760859 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 11 May 2016 00:12:09 +0200 Subject: evaluate: transfer right shifts to set reference side This provides a generic way to transfer shifts from the left hand side to the right hand range side of a relational expression when performing transformations from the evaluation step. Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 40 +++++++++++++++++++++++++++++++ src/netlink_delinearize.c | 60 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 94 insertions(+), 6 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 60bbce1b..72a0e435 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1172,6 +1172,46 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr) list_add_tail(&i->list, &next->list); } break; + case EXPR_SET_REF: + list_for_each_entry(i, &(*expr)->right->set->init->expressions, list) { + switch (i->key->ops->type) { + case EXPR_VALUE: + err = binop_can_transfer(ctx, left, i->key); + if (err <= 0) + return err; + break; + case EXPR_RANGE: + err = binop_can_transfer(ctx, left, i->key->left); + if (err <= 0) + return err; + err = binop_can_transfer(ctx, left, i->key->right); + if (err <= 0) + return err; + break; + default: + break; + } + } + list_for_each_entry_safe(i, next, &(*expr)->right->set->init->expressions, + list) { + list_del(&i->list); + switch (i->key->ops->type) { + case EXPR_VALUE: + if (binop_transfer_one(ctx, left, &i->key) < 0) + return -1; + break; + case EXPR_RANGE: + if (binop_transfer_one(ctx, left, &i->key->left) < 0) + return -1; + if (binop_transfer_one(ctx, left, &i->key->right) < 0) + return -1; + break; + default: + break; + } + list_add_tail(&i->list, &next->list); + } + break; default: return 0; } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 84f94fc3..eb07ffbe 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -1185,9 +1185,61 @@ static struct expr *binop_tree_to_list(struct expr *list, struct expr *expr) return list; } +static void binop_adjust_one(const struct expr *binop, struct expr *value, + unsigned int shift) +{ + struct expr *left = binop->left; + + assert(value->len >= binop->right->len); + + mpz_rshift_ui(value->value, shift); + switch (left->ops->type) { + case EXPR_PAYLOAD: + case EXPR_EXTHDR: + value->len = left->len; + break; + default: + BUG("unknown expression type %s\n", left->ops->name); + break; + } +} + +static void binop_adjust(struct expr *expr, unsigned int shift) +{ + const struct expr *binop = expr->left; + struct expr *right = expr->right, *i; + + switch (right->ops->type) { + case EXPR_VALUE: + binop_adjust_one(binop, right, shift); + break; + case EXPR_SET_REF: + list_for_each_entry(i, &right->set->init->expressions, list) { + switch (i->key->ops->type) { + case EXPR_VALUE: + binop_adjust_one(binop, i->key, shift); + break; + case EXPR_RANGE: + binop_adjust_one(binop, i->key->left, shift); + binop_adjust_one(binop, i->key->right, shift); + break; + case EXPR_SET_ELEM: + binop_adjust_one(binop, i->key->key, shift); + break; + default: + BUG("unknown expression type %s\n", i->key->ops->name); + } + } + break; + default: + BUG("unknown expression type %s\n", expr->ops->name); + break; + } +} + static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr) { - struct expr *binop = expr->left, *value = expr->right; + struct expr *binop = expr->left; struct expr *left = binop->left; struct expr *mask = binop->right; unsigned int shift; @@ -1205,11 +1257,7 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr) * Finally, convert the expression to 1) by replacing * the binop with the binop payload/exthdr expression. */ - if (value->ops->type == EXPR_VALUE) { - assert(value->len >= expr->left->right->len); - mpz_rshift_ui(value->value, shift); - value->len = left->len; - } + binop_adjust(expr, shift); assert(expr->left->ops->type == EXPR_BINOP); assert(binop->left == left); -- cgit v1.2.3