Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: bitwise: add support for doing AND, OR and XOR directly

Hitherto, these operations have been converted in user space to
mask-and-xor operations on one register and two immediate values, and it
is the latter which have been evaluated by the kernel. We add support
for evaluating these operations directly in kernel space on one register
and either an immediate value or a second register.

Pablo made a few changes to the original patch:

- EINVAL if NFTA_BITWISE_SREG2 is used with fast version.
- Allow _AND,_OR,_XOR with _DATA != sizeof(u32)
- Dump _SREG2 or _DATA with _AND,_OR,_XOR

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Jeremy Sowden and committed by
Pablo Neira Ayuso
b0ccf4f5 a12143e6

+131 -11
+8
include/uapi/linux/netfilter/nf_tables.h
··· 568 568 * and XOR boolean operations 569 569 * @NFT_BITWISE_LSHIFT: left-shift operation 570 570 * @NFT_BITWISE_RSHIFT: right-shift operation 571 + * @NFT_BITWISE_AND: and operation 572 + * @NFT_BITWISE_OR: or operation 573 + * @NFT_BITWISE_XOR: xor operation 571 574 */ 572 575 enum nft_bitwise_ops { 573 576 NFT_BITWISE_MASK_XOR, 574 577 NFT_BITWISE_LSHIFT, 575 578 NFT_BITWISE_RSHIFT, 579 + NFT_BITWISE_AND, 580 + NFT_BITWISE_OR, 581 + NFT_BITWISE_XOR, 576 582 }; 577 583 /* 578 584 * Old name for NFT_BITWISE_MASK_XOR. Retained for backwards-compatibility. ··· 596 590 * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) 597 591 * @NFTA_BITWISE_DATA: argument for non-boolean operations 598 592 * (NLA_NESTED: nft_data_attributes) 593 + * @NFTA_BITWISE_SREG2: second source register (NLA_U32: nft_registers) 599 594 * 600 595 * The bitwise expression supports boolean and shift operations. It implements 601 596 * the boolean operations by performing the following operation: ··· 620 613 NFTA_BITWISE_XOR, 621 614 NFTA_BITWISE_OP, 622 615 NFTA_BITWISE_DATA, 616 + NFTA_BITWISE_SREG2, 623 617 __NFTA_BITWISE_MAX 624 618 }; 625 619 #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
+123 -11
net/netfilter/nft_bitwise.c
··· 17 17 18 18 struct nft_bitwise { 19 19 u8 sreg; 20 + u8 sreg2; 20 21 u8 dreg; 21 22 enum nft_bitwise_ops op:8; 22 23 u8 len; ··· 61 60 } 62 61 } 63 62 63 + static void nft_bitwise_eval_and(u32 *dst, const u32 *src, const u32 *src2, 64 + const struct nft_bitwise *priv) 65 + { 66 + unsigned int i, n; 67 + 68 + for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++) 69 + dst[i] = src[i] & src2[i]; 70 + } 71 + 72 + static void nft_bitwise_eval_or(u32 *dst, const u32 *src, const u32 *src2, 73 + const struct nft_bitwise *priv) 74 + { 75 + unsigned int i, n; 76 + 77 + for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++) 78 + dst[i] = src[i] | src2[i]; 79 + } 80 + 81 + static void nft_bitwise_eval_xor(u32 *dst, const u32 *src, const u32 *src2, 82 + const struct nft_bitwise *priv) 83 + { 84 + unsigned int i, n; 85 + 86 + for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++) 87 + dst[i] = src[i] ^ src2[i]; 88 + } 89 + 64 90 void nft_bitwise_eval(const struct nft_expr *expr, 65 91 struct nft_regs *regs, const struct nft_pktinfo *pkt) 66 92 { 67 93 const struct nft_bitwise *priv = nft_expr_priv(expr); 68 - const u32 *src = &regs->data[priv->sreg]; 94 + const u32 *src = &regs->data[priv->sreg], *src2; 69 95 u32 *dst = &regs->data[priv->dreg]; 70 96 71 - switch (priv->op) { 72 - case NFT_BITWISE_MASK_XOR: 97 + if (priv->op == NFT_BITWISE_MASK_XOR) { 73 98 nft_bitwise_eval_mask_xor(dst, src, priv); 74 - break; 75 - case NFT_BITWISE_LSHIFT: 99 + return; 100 + } 101 + if (priv->op == NFT_BITWISE_LSHIFT) { 76 102 nft_bitwise_eval_lshift(dst, src, priv); 77 - break; 78 - case NFT_BITWISE_RSHIFT: 103 + return; 104 + } 105 + if (priv->op == NFT_BITWISE_RSHIFT) { 79 106 nft_bitwise_eval_rshift(dst, src, priv); 80 - break; 107 + return; 108 + } 109 + 110 + src2 = priv->sreg2 ? &regs->data[priv->sreg2] : priv->data.data; 111 + 112 + if (priv->op == NFT_BITWISE_AND) { 113 + nft_bitwise_eval_and(dst, src, src2, priv); 114 + return; 115 + } 116 + if (priv->op == NFT_BITWISE_OR) { 117 + nft_bitwise_eval_or(dst, src, src2, priv); 118 + return; 119 + } 120 + if (priv->op == NFT_BITWISE_XOR) { 121 + nft_bitwise_eval_xor(dst, src, src2, priv); 122 + return; 81 123 } 82 124 } 83 125 84 126 static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { 85 127 [NFTA_BITWISE_SREG] = { .type = NLA_U32 }, 128 + [NFTA_BITWISE_SREG2] = { .type = NLA_U32 }, 86 129 [NFTA_BITWISE_DREG] = { .type = NLA_U32 }, 87 130 [NFTA_BITWISE_LEN] = { .type = NLA_U32 }, 88 131 [NFTA_BITWISE_MASK] = { .type = NLA_NESTED }, ··· 150 105 }; 151 106 int err; 152 107 153 - if (tb[NFTA_BITWISE_DATA]) 108 + if (tb[NFTA_BITWISE_DATA] || 109 + tb[NFTA_BITWISE_SREG2]) 154 110 return -EINVAL; 155 111 156 112 if (!tb[NFTA_BITWISE_MASK] || ··· 185 139 int err; 186 140 187 141 if (tb[NFTA_BITWISE_MASK] || 188 - tb[NFTA_BITWISE_XOR]) 142 + tb[NFTA_BITWISE_XOR] || 143 + tb[NFTA_BITWISE_SREG2]) 189 144 return -EINVAL; 190 145 191 146 if (!tb[NFTA_BITWISE_DATA]) ··· 199 152 if (priv->data.data[0] >= BITS_PER_TYPE(u32)) { 200 153 nft_data_release(&priv->data, desc.type); 201 154 return -EINVAL; 155 + } 156 + 157 + return 0; 158 + } 159 + 160 + static int nft_bitwise_init_bool(const struct nft_ctx *ctx, 161 + struct nft_bitwise *priv, 162 + const struct nlattr *const tb[]) 163 + { 164 + int err; 165 + 166 + if (tb[NFTA_BITWISE_MASK] || 167 + tb[NFTA_BITWISE_XOR]) 168 + return -EINVAL; 169 + 170 + if ((!tb[NFTA_BITWISE_DATA] && !tb[NFTA_BITWISE_SREG2]) || 171 + (tb[NFTA_BITWISE_DATA] && tb[NFTA_BITWISE_SREG2])) 172 + return -EINVAL; 173 + 174 + if (tb[NFTA_BITWISE_DATA]) { 175 + struct nft_data_desc desc = { 176 + .type = NFT_DATA_VALUE, 177 + .size = sizeof(priv->data), 178 + .len = priv->len, 179 + }; 180 + 181 + err = nft_data_init(NULL, &priv->data, &desc, 182 + tb[NFTA_BITWISE_DATA]); 183 + if (err < 0) 184 + return err; 185 + } else { 186 + err = nft_parse_register_load(ctx, tb[NFTA_BITWISE_SREG2], 187 + &priv->sreg2, priv->len); 188 + if (err < 0) 189 + return err; 202 190 } 203 191 204 192 return 0; ··· 270 188 case NFT_BITWISE_MASK_XOR: 271 189 case NFT_BITWISE_LSHIFT: 272 190 case NFT_BITWISE_RSHIFT: 191 + case NFT_BITWISE_AND: 192 + case NFT_BITWISE_OR: 193 + case NFT_BITWISE_XOR: 273 194 break; 274 195 default: 275 196 return -EOPNOTSUPP; ··· 288 203 case NFT_BITWISE_LSHIFT: 289 204 case NFT_BITWISE_RSHIFT: 290 205 err = nft_bitwise_init_shift(priv, tb); 206 + break; 207 + case NFT_BITWISE_AND: 208 + case NFT_BITWISE_OR: 209 + case NFT_BITWISE_XOR: 210 + err = nft_bitwise_init_bool(ctx, priv, tb); 291 211 break; 292 212 } 293 213 ··· 322 232 return 0; 323 233 } 324 234 235 + static int nft_bitwise_dump_bool(struct sk_buff *skb, 236 + const struct nft_bitwise *priv) 237 + { 238 + if (priv->sreg2) { 239 + if (nft_dump_register(skb, NFTA_BITWISE_SREG2, priv->sreg2)) 240 + return -1; 241 + } else { 242 + if (nft_data_dump(skb, NFTA_BITWISE_DATA, &priv->data, 243 + NFT_DATA_VALUE, sizeof(u32)) < 0) 244 + return -1; 245 + } 246 + 247 + return 0; 248 + } 249 + 325 250 static int nft_bitwise_dump(struct sk_buff *skb, 326 251 const struct nft_expr *expr, bool reset) 327 252 { ··· 359 254 case NFT_BITWISE_LSHIFT: 360 255 case NFT_BITWISE_RSHIFT: 361 256 err = nft_bitwise_dump_shift(skb, priv); 257 + break; 258 + case NFT_BITWISE_AND: 259 + case NFT_BITWISE_OR: 260 + case NFT_BITWISE_XOR: 261 + err = nft_bitwise_dump_bool(skb, priv); 362 262 break; 363 263 } 364 264 ··· 409 299 track->regs[priv->dreg].bitwise && 410 300 track->regs[priv->dreg].bitwise->ops == expr->ops && 411 301 priv->sreg == bitwise->sreg && 302 + priv->sreg2 == bitwise->sreg2 && 412 303 priv->dreg == bitwise->dreg && 413 304 priv->op == bitwise->op && 414 305 priv->len == bitwise->len && ··· 486 375 if (err < 0) 487 376 return err; 488 377 489 - if (tb[NFTA_BITWISE_DATA]) 378 + if (tb[NFTA_BITWISE_DATA] || 379 + tb[NFTA_BITWISE_SREG2]) 490 380 return -EINVAL; 491 381 492 382 if (!tb[NFTA_BITWISE_MASK] ||