Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
0004  *
0005  * Development of this code funded by Astaro AG (http://www.astaro.com/)
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 = &regs->data[priv->sreg];
0068     u32 *dst = &regs->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(&reg->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, /* inlined */
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);