diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-12-05 20:04:21 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-12-14 20:32:55 +0100 |
commit | 4a9a38727957731e56b5302960da5ef1e0275d61 (patch) | |
tree | b3d3c546cc6db893866c8d4707861dd06c2a8963 /src/netlink_delinearize.c | |
parent | 210f479bff5b6cf8483383aa27ad9ded3925326c (diff) |
src: fix sub-byte protocol header definitions
Update bitfield definitions to match according to the way they are
expressed in RFC and IEEE specifications.
This required a bit of update for c3f0501 ("src: netlink_linearize:
handle sub-byte lengths").
>From the linearize step, to calculate the shift based on the bitfield
offset, we need to obtain the length of the word in bytes:
len = round_up(expr->len, BITS_PER_BYTE);
Then, we substract the offset bits and the bitfield length.
shift = len - (offset + expr->len);
From the delinearize, payload_expr_trim() needs to obtain the real
offset through:
off = round_up(mask->len, BITS_PER_BYTE) - mask_len;
For vlan id (offset 12), this gets the position of the last bit set in
the mask (ie. 12), then we substract the length we fetch in bytes (16),
so we obtain the real bitfield offset (4).
Then, we add that to the original payload offset that was expressed in
bytes:
payload_offset += off;
Note that payload_expr_trim() now also adjusts the payload expression to
its real length and offset so we don't need to propagate the mask
expression.
Reported-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/netlink_delinearize.c')
-rw-r--r-- | src/netlink_delinearize.c | 23 |
1 files changed, 10 insertions, 13 deletions
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 3e1f912c..e5cee163 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -998,8 +998,7 @@ static void integer_type_postprocess(struct expr *expr) static void payload_match_expand(struct rule_pp_ctx *ctx, struct expr *expr, - struct expr *payload, - struct expr *mask) + struct expr *payload) { struct expr *left = payload, *right = expr->right, *tmp; struct list_head list = LIST_HEAD_INIT(list); @@ -1008,7 +1007,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, enum proto_bases base = left->payload.base; const struct expr_ops *payload_ops = left->ops; - payload_expr_expand(&list, left, mask, &ctx->pctx); + payload_expr_expand(&list, left, &ctx->pctx); list_for_each_entry(left, &list, list) { tmp = constant_expr_splice(right, left->len); @@ -1063,8 +1062,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, static void payload_match_postprocess(struct rule_pp_ctx *ctx, struct expr *expr, - struct expr *payload, - struct expr *mask) + struct expr *payload) { enum proto_bases base = payload->payload.base; @@ -1075,7 +1073,7 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, case OP_EQ: case OP_NEQ: if (expr->right->ops->type == EXPR_VALUE) { - payload_match_expand(ctx, expr, payload, mask); + payload_match_expand(ctx, expr, payload); break; } /* Fall through */ @@ -1190,6 +1188,7 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e binop->right->ops->type == EXPR_VALUE) { struct expr *payload = binop->left; struct expr *mask = binop->right; + unsigned int shift; /* * This *might* be a payload match testing header fields that @@ -1214,7 +1213,7 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e * payload_expr_trim will figure out if the mask is needed to match * templates. */ - if (payload_expr_trim(payload, mask, &ctx->pctx)) { + if (payload_expr_trim(payload, mask, &ctx->pctx, &shift)) { /* mask is implicit, binop needs to be removed. * * Fix all values of the expression according to the mask @@ -1226,13 +1225,11 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e */ if (value->ops->type == EXPR_VALUE) { assert(value->len >= expr->left->right->len); - value->len = mask->len; + mpz_rshift_ui(value->value, shift); + value->len = payload->len; } - payload->len = mask->len; - payload->payload.offset += mpz_scan1(mask->value, 0); - - payload_match_postprocess(ctx, expr, payload, mask); + payload_match_postprocess(ctx, expr, payload); assert(expr->left->ops->type == EXPR_BINOP); @@ -1383,7 +1380,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) case EXPR_RELATIONAL: switch (expr->left->ops->type) { case EXPR_PAYLOAD: - payload_match_postprocess(ctx, expr, expr->left, NULL); + payload_match_postprocess(ctx, expr, expr->left); return; default: expr_postprocess(ctx, &expr->left); |