0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/init.h>
0010 #include <linux/module.h>
0011 #include <linux/netlink.h>
0012 #include <linux/netfilter.h>
0013 #include <linux/netfilter/nf_tables.h>
0014 #include <net/netfilter/nf_tables_core.h>
0015 #include <net/netfilter/nf_tables.h>
0016 #include <net/netfilter/nf_tables_offload.h>
0017
0018 struct nft_bitwise {
0019 u8 sreg;
0020 u8 dreg;
0021 enum nft_bitwise_ops op:8;
0022 u8 len;
0023 struct nft_data mask;
0024 struct nft_data xor;
0025 struct nft_data data;
0026 };
0027
0028 static void nft_bitwise_eval_bool(u32 *dst, const u32 *src,
0029 const struct nft_bitwise *priv)
0030 {
0031 unsigned int i;
0032
0033 for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++)
0034 dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
0035 }
0036
0037 static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src,
0038 const struct nft_bitwise *priv)
0039 {
0040 u32 shift = priv->data.data[0];
0041 unsigned int i;
0042 u32 carry = 0;
0043
0044 for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) {
0045 dst[i - 1] = (src[i - 1] << shift) | carry;
0046 carry = src[i - 1] >> (BITS_PER_TYPE(u32) - shift);
0047 }
0048 }
0049
0050 static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src,
0051 const struct nft_bitwise *priv)
0052 {
0053 u32 shift = priv->data.data[0];
0054 unsigned int i;
0055 u32 carry = 0;
0056
0057 for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) {
0058 dst[i] = carry | (src[i] >> shift);
0059 carry = src[i] << (BITS_PER_TYPE(u32) - shift);
0060 }
0061 }
0062
0063 void nft_bitwise_eval(const struct nft_expr *expr,
0064 struct nft_regs *regs, const struct nft_pktinfo *pkt)
0065 {
0066 const struct nft_bitwise *priv = nft_expr_priv(expr);
0067 const u32 *src = ®s->data[priv->sreg];
0068 u32 *dst = ®s->data[priv->dreg];
0069
0070 switch (priv->op) {
0071 case NFT_BITWISE_BOOL:
0072 nft_bitwise_eval_bool(dst, src, priv);
0073 break;
0074 case NFT_BITWISE_LSHIFT:
0075 nft_bitwise_eval_lshift(dst, src, priv);
0076 break;
0077 case NFT_BITWISE_RSHIFT:
0078 nft_bitwise_eval_rshift(dst, src, priv);
0079 break;
0080 }
0081 }
0082
0083 static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
0084 [NFTA_BITWISE_SREG] = { .type = NLA_U32 },
0085 [NFTA_BITWISE_DREG] = { .type = NLA_U32 },
0086 [NFTA_BITWISE_LEN] = { .type = NLA_U32 },
0087 [NFTA_BITWISE_MASK] = { .type = NLA_NESTED },
0088 [NFTA_BITWISE_XOR] = { .type = NLA_NESTED },
0089 [NFTA_BITWISE_OP] = { .type = NLA_U32 },
0090 [NFTA_BITWISE_DATA] = { .type = NLA_NESTED },
0091 };
0092
0093 static int nft_bitwise_init_bool(struct nft_bitwise *priv,
0094 const struct nlattr *const tb[])
0095 {
0096 struct nft_data_desc mask = {
0097 .type = NFT_DATA_VALUE,
0098 .size = sizeof(priv->mask),
0099 .len = priv->len,
0100 };
0101 struct nft_data_desc xor = {
0102 .type = NFT_DATA_VALUE,
0103 .size = sizeof(priv->xor),
0104 .len = priv->len,
0105 };
0106 int err;
0107
0108 if (tb[NFTA_BITWISE_DATA])
0109 return -EINVAL;
0110
0111 if (!tb[NFTA_BITWISE_MASK] ||
0112 !tb[NFTA_BITWISE_XOR])
0113 return -EINVAL;
0114
0115 err = nft_data_init(NULL, &priv->mask, &mask, tb[NFTA_BITWISE_MASK]);
0116 if (err < 0)
0117 return err;
0118
0119 err = nft_data_init(NULL, &priv->xor, &xor, tb[NFTA_BITWISE_XOR]);
0120 if (err < 0)
0121 goto err_xor_err;
0122
0123 return 0;
0124
0125 err_xor_err:
0126 nft_data_release(&priv->mask, mask.type);
0127
0128 return err;
0129 }
0130
0131 static int nft_bitwise_init_shift(struct nft_bitwise *priv,
0132 const struct nlattr *const tb[])
0133 {
0134 struct nft_data_desc desc = {
0135 .type = NFT_DATA_VALUE,
0136 .size = sizeof(priv->data),
0137 .len = sizeof(u32),
0138 };
0139 int err;
0140
0141 if (tb[NFTA_BITWISE_MASK] ||
0142 tb[NFTA_BITWISE_XOR])
0143 return -EINVAL;
0144
0145 if (!tb[NFTA_BITWISE_DATA])
0146 return -EINVAL;
0147
0148 err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_BITWISE_DATA]);
0149 if (err < 0)
0150 return err;
0151
0152 if (priv->data.data[0] >= BITS_PER_TYPE(u32)) {
0153 nft_data_release(&priv->data, desc.type);
0154 return -EINVAL;
0155 }
0156
0157 return 0;
0158 }
0159
0160 static int nft_bitwise_init(const struct nft_ctx *ctx,
0161 const struct nft_expr *expr,
0162 const struct nlattr * const tb[])
0163 {
0164 struct nft_bitwise *priv = nft_expr_priv(expr);
0165 u32 len;
0166 int err;
0167
0168 err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
0169 if (err < 0)
0170 return err;
0171
0172 priv->len = len;
0173
0174 err = nft_parse_register_load(tb[NFTA_BITWISE_SREG], &priv->sreg,
0175 priv->len);
0176 if (err < 0)
0177 return err;
0178
0179 err = nft_parse_register_store(ctx, tb[NFTA_BITWISE_DREG],
0180 &priv->dreg, NULL, NFT_DATA_VALUE,
0181 priv->len);
0182 if (err < 0)
0183 return err;
0184
0185 if (tb[NFTA_BITWISE_OP]) {
0186 priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP]));
0187 switch (priv->op) {
0188 case NFT_BITWISE_BOOL:
0189 case NFT_BITWISE_LSHIFT:
0190 case NFT_BITWISE_RSHIFT:
0191 break;
0192 default:
0193 return -EOPNOTSUPP;
0194 }
0195 } else {
0196 priv->op = NFT_BITWISE_BOOL;
0197 }
0198
0199 switch(priv->op) {
0200 case NFT_BITWISE_BOOL:
0201 err = nft_bitwise_init_bool(priv, tb);
0202 break;
0203 case NFT_BITWISE_LSHIFT:
0204 case NFT_BITWISE_RSHIFT:
0205 err = nft_bitwise_init_shift(priv, tb);
0206 break;
0207 }
0208
0209 return err;
0210 }
0211
0212 static int nft_bitwise_dump_bool(struct sk_buff *skb,
0213 const struct nft_bitwise *priv)
0214 {
0215 if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
0216 NFT_DATA_VALUE, priv->len) < 0)
0217 return -1;
0218
0219 if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
0220 NFT_DATA_VALUE, priv->len) < 0)
0221 return -1;
0222
0223 return 0;
0224 }
0225
0226 static int nft_bitwise_dump_shift(struct sk_buff *skb,
0227 const struct nft_bitwise *priv)
0228 {
0229 if (nft_data_dump(skb, NFTA_BITWISE_DATA, &priv->data,
0230 NFT_DATA_VALUE, sizeof(u32)) < 0)
0231 return -1;
0232 return 0;
0233 }
0234
0235 static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
0236 {
0237 const struct nft_bitwise *priv = nft_expr_priv(expr);
0238 int err = 0;
0239
0240 if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
0241 return -1;
0242 if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
0243 return -1;
0244 if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
0245 return -1;
0246 if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(priv->op)))
0247 return -1;
0248
0249 switch (priv->op) {
0250 case NFT_BITWISE_BOOL:
0251 err = nft_bitwise_dump_bool(skb, priv);
0252 break;
0253 case NFT_BITWISE_LSHIFT:
0254 case NFT_BITWISE_RSHIFT:
0255 err = nft_bitwise_dump_shift(skb, priv);
0256 break;
0257 }
0258
0259 return err;
0260 }
0261
0262 static struct nft_data zero;
0263
0264 static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
0265 struct nft_flow_rule *flow,
0266 const struct nft_expr *expr)
0267 {
0268 const struct nft_bitwise *priv = nft_expr_priv(expr);
0269 struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
0270
0271 if (priv->op != NFT_BITWISE_BOOL)
0272 return -EOPNOTSUPP;
0273
0274 if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) ||
0275 priv->sreg != priv->dreg || priv->len != reg->len)
0276 return -EOPNOTSUPP;
0277
0278 memcpy(®->mask, &priv->mask, sizeof(priv->mask));
0279
0280 return 0;
0281 }
0282
0283 static bool nft_bitwise_reduce(struct nft_regs_track *track,
0284 const struct nft_expr *expr)
0285 {
0286 const struct nft_bitwise *priv = nft_expr_priv(expr);
0287 const struct nft_bitwise *bitwise;
0288 unsigned int regcount;
0289 u8 dreg;
0290 int i;
0291
0292 if (!track->regs[priv->sreg].selector)
0293 return false;
0294
0295 bitwise = nft_expr_priv(track->regs[priv->dreg].selector);
0296 if (track->regs[priv->sreg].selector == track->regs[priv->dreg].selector &&
0297 track->regs[priv->sreg].num_reg == 0 &&
0298 track->regs[priv->dreg].bitwise &&
0299 track->regs[priv->dreg].bitwise->ops == expr->ops &&
0300 priv->sreg == bitwise->sreg &&
0301 priv->dreg == bitwise->dreg &&
0302 priv->op == bitwise->op &&
0303 priv->len == bitwise->len &&
0304 !memcmp(&priv->mask, &bitwise->mask, sizeof(priv->mask)) &&
0305 !memcmp(&priv->xor, &bitwise->xor, sizeof(priv->xor)) &&
0306 !memcmp(&priv->data, &bitwise->data, sizeof(priv->data))) {
0307 track->cur = expr;
0308 return true;
0309 }
0310
0311 if (track->regs[priv->sreg].bitwise ||
0312 track->regs[priv->sreg].num_reg != 0) {
0313 nft_reg_track_cancel(track, priv->dreg, priv->len);
0314 return false;
0315 }
0316
0317 if (priv->sreg != priv->dreg) {
0318 nft_reg_track_update(track, track->regs[priv->sreg].selector,
0319 priv->dreg, priv->len);
0320 }
0321
0322 dreg = priv->dreg;
0323 regcount = DIV_ROUND_UP(priv->len, NFT_REG32_SIZE);
0324 for (i = 0; i < regcount; i++, dreg++)
0325 track->regs[priv->dreg].bitwise = expr;
0326
0327 return false;
0328 }
0329
0330 static const struct nft_expr_ops nft_bitwise_ops = {
0331 .type = &nft_bitwise_type,
0332 .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
0333 .eval = nft_bitwise_eval,
0334 .init = nft_bitwise_init,
0335 .dump = nft_bitwise_dump,
0336 .reduce = nft_bitwise_reduce,
0337 .offload = nft_bitwise_offload,
0338 };
0339
0340 static int
0341 nft_bitwise_extract_u32_data(const struct nlattr * const tb, u32 *out)
0342 {
0343 struct nft_data data;
0344 struct nft_data_desc desc = {
0345 .type = NFT_DATA_VALUE,
0346 .size = sizeof(data),
0347 .len = sizeof(u32),
0348 };
0349 int err;
0350
0351 err = nft_data_init(NULL, &data, &desc, tb);
0352 if (err < 0)
0353 return err;
0354
0355 *out = data.data[0];
0356
0357 return 0;
0358 }
0359
0360 static int nft_bitwise_fast_init(const struct nft_ctx *ctx,
0361 const struct nft_expr *expr,
0362 const struct nlattr * const tb[])
0363 {
0364 struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
0365 int err;
0366
0367 err = nft_parse_register_load(tb[NFTA_BITWISE_SREG], &priv->sreg,
0368 sizeof(u32));
0369 if (err < 0)
0370 return err;
0371
0372 err = nft_parse_register_store(ctx, tb[NFTA_BITWISE_DREG], &priv->dreg,
0373 NULL, NFT_DATA_VALUE, sizeof(u32));
0374 if (err < 0)
0375 return err;
0376
0377 if (tb[NFTA_BITWISE_DATA])
0378 return -EINVAL;
0379
0380 if (!tb[NFTA_BITWISE_MASK] ||
0381 !tb[NFTA_BITWISE_XOR])
0382 return -EINVAL;
0383
0384 err = nft_bitwise_extract_u32_data(tb[NFTA_BITWISE_MASK], &priv->mask);
0385 if (err < 0)
0386 return err;
0387
0388 err = nft_bitwise_extract_u32_data(tb[NFTA_BITWISE_XOR], &priv->xor);
0389 if (err < 0)
0390 return err;
0391
0392 return 0;
0393 }
0394
0395 static int
0396 nft_bitwise_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
0397 {
0398 const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
0399 struct nft_data data;
0400
0401 if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
0402 return -1;
0403 if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
0404 return -1;
0405 if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(sizeof(u32))))
0406 return -1;
0407 if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_BOOL)))
0408 return -1;
0409
0410 data.data[0] = priv->mask;
0411 if (nft_data_dump(skb, NFTA_BITWISE_MASK, &data,
0412 NFT_DATA_VALUE, sizeof(u32)) < 0)
0413 return -1;
0414
0415 data.data[0] = priv->xor;
0416 if (nft_data_dump(skb, NFTA_BITWISE_XOR, &data,
0417 NFT_DATA_VALUE, sizeof(u32)) < 0)
0418 return -1;
0419
0420 return 0;
0421 }
0422
0423 static int nft_bitwise_fast_offload(struct nft_offload_ctx *ctx,
0424 struct nft_flow_rule *flow,
0425 const struct nft_expr *expr)
0426 {
0427 const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
0428 struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
0429
0430 if (priv->xor || priv->sreg != priv->dreg || reg->len != sizeof(u32))
0431 return -EOPNOTSUPP;
0432
0433 reg->mask.data[0] = priv->mask;
0434 return 0;
0435 }
0436
0437 static bool nft_bitwise_fast_reduce(struct nft_regs_track *track,
0438 const struct nft_expr *expr)
0439 {
0440 const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
0441 const struct nft_bitwise_fast_expr *bitwise;
0442
0443 if (!track->regs[priv->sreg].selector)
0444 return false;
0445
0446 bitwise = nft_expr_priv(track->regs[priv->dreg].selector);
0447 if (track->regs[priv->sreg].selector == track->regs[priv->dreg].selector &&
0448 track->regs[priv->dreg].bitwise &&
0449 track->regs[priv->dreg].bitwise->ops == expr->ops &&
0450 priv->sreg == bitwise->sreg &&
0451 priv->dreg == bitwise->dreg &&
0452 priv->mask == bitwise->mask &&
0453 priv->xor == bitwise->xor) {
0454 track->cur = expr;
0455 return true;
0456 }
0457
0458 if (track->regs[priv->sreg].bitwise) {
0459 nft_reg_track_cancel(track, priv->dreg, NFT_REG32_SIZE);
0460 return false;
0461 }
0462
0463 if (priv->sreg != priv->dreg) {
0464 track->regs[priv->dreg].selector =
0465 track->regs[priv->sreg].selector;
0466 }
0467 track->regs[priv->dreg].bitwise = expr;
0468
0469 return false;
0470 }
0471
0472 const struct nft_expr_ops nft_bitwise_fast_ops = {
0473 .type = &nft_bitwise_type,
0474 .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise_fast_expr)),
0475 .eval = NULL,
0476 .init = nft_bitwise_fast_init,
0477 .dump = nft_bitwise_fast_dump,
0478 .reduce = nft_bitwise_fast_reduce,
0479 .offload = nft_bitwise_fast_offload,
0480 };
0481
0482 static const struct nft_expr_ops *
0483 nft_bitwise_select_ops(const struct nft_ctx *ctx,
0484 const struct nlattr * const tb[])
0485 {
0486 int err;
0487 u32 len;
0488
0489 if (!tb[NFTA_BITWISE_LEN] ||
0490 !tb[NFTA_BITWISE_SREG] ||
0491 !tb[NFTA_BITWISE_DREG])
0492 return ERR_PTR(-EINVAL);
0493
0494 err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
0495 if (err < 0)
0496 return ERR_PTR(err);
0497
0498 if (len != sizeof(u32))
0499 return &nft_bitwise_ops;
0500
0501 if (tb[NFTA_BITWISE_OP] &&
0502 ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_BOOL)
0503 return &nft_bitwise_ops;
0504
0505 return &nft_bitwise_fast_ops;
0506 }
0507
0508 struct nft_expr_type nft_bitwise_type __read_mostly = {
0509 .name = "bitwise",
0510 .select_ops = nft_bitwise_select_ops,
0511 .policy = nft_bitwise_policy,
0512 .maxattr = NFTA_BITWISE_MAX,
0513 .owner = THIS_MODULE,
0514 };
0515
0516 bool nft_expr_reduce_bitwise(struct nft_regs_track *track,
0517 const struct nft_expr *expr)
0518 {
0519 const struct nft_expr *last = track->last;
0520 const struct nft_expr *next;
0521
0522 if (expr == last)
0523 return false;
0524
0525 next = nft_expr_next(expr);
0526 if (next->ops == &nft_bitwise_ops)
0527 return nft_bitwise_reduce(track, next);
0528 else if (next->ops == &nft_bitwise_fast_ops)
0529 return nft_bitwise_fast_reduce(track, next);
0530
0531 return false;
0532 }
0533 EXPORT_SYMBOL_GPL(nft_expr_reduce_bitwise);