summaryrefslogtreecommitdiffstats
path: root/src/netlink_delinearize.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2015-12-05 20:04:21 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2015-12-14 20:32:55 +0100
commit4a9a38727957731e56b5302960da5ef1e0275d61 (patch)
treeb3d3c546cc6db893866c8d4707861dd06c2a8963 /src/netlink_delinearize.c
parent210f479bff5b6cf8483383aa27ad9ded3925326c (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.c23
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);