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

netfilter: reduce NF_VERDICT_MASK to 0xff

NF_VERDICT_MASK is currently 0xffff. This is because the upper
16 bits are used to store errno (for NF_DROP) or the queue number
(NF_QUEUE verdict).

As there are up to 0xffff different queues available, there is no more
room to store additional flags.

At the moment there are only 6 different verdicts, i.e. we can reduce
NF_VERDICT_MASK to 0xff to allow storing additional flags in the 0xff00 space.

NF_VERDICT_BITS would then be reduced to 8, but because the value is
exported to userspace, this might cause breakage; e.g.:

e.g. 'queuenr = (1 << NF_VERDICT_BITS) | NF_QUEUE' would now break.

Thus, remove NF_VERDICT_BITS usage in the kernel and move the old value
to the 'userspace compat' section.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Florian Westphal and committed by
Patrick McHardy
f615df76 06cdb634

+18 -8
+15 -5
include/linux/netfilter.h
··· 24 24 #define NF_MAX_VERDICT NF_STOP 25 25 26 26 /* we overload the higher bits for encoding auxiliary data such as the queue 27 - * number. Not nice, but better than additional function arguments. */ 28 - #define NF_VERDICT_MASK 0x0000ffff 29 - #define NF_VERDICT_BITS 16 27 + * number or errno values. Not nice, but better than additional function 28 + * arguments. */ 29 + #define NF_VERDICT_MASK 0x000000ff 30 30 31 + /* extra verdict flags have mask 0x0000ff00 */ 32 + 33 + /* queue number (NF_QUEUE) or errno (NF_DROP) */ 31 34 #define NF_VERDICT_QMASK 0xffff0000 32 35 #define NF_VERDICT_QBITS 16 33 36 34 - #define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE) 37 + #define NF_QUEUE_NR(x) ((((x) << 16) & NF_VERDICT_QMASK) | NF_QUEUE) 35 38 36 - #define NF_DROP_ERR(x) (((-x) << NF_VERDICT_BITS) | NF_DROP) 39 + #define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP) 37 40 38 41 /* only for userspace compatibility */ 39 42 #ifndef __KERNEL__ ··· 44 41 <= 0x2000 is used for protocol-flags. */ 45 42 #define NFC_UNKNOWN 0x4000 46 43 #define NFC_ALTERED 0x8000 44 + 45 + /* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */ 46 + #define NF_VERDICT_BITS 16 47 47 #endif 48 48 49 49 enum nf_inet_hooks { ··· 78 72 79 73 #ifdef __KERNEL__ 80 74 #ifdef CONFIG_NETFILTER 75 + static inline int NF_DROP_GETERR(int verdict) 76 + { 77 + return -(verdict >> NF_VERDICT_QBITS); 78 + } 81 79 82 80 static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1, 83 81 const union nf_inet_addr *a2)
+2 -2
net/netfilter/core.c
··· 175 175 ret = 1; 176 176 } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { 177 177 kfree_skb(skb); 178 - ret = -(verdict >> NF_VERDICT_BITS); 178 + ret = NF_DROP_GETERR(verdict); 179 179 if (ret == 0) 180 180 ret = -EPERM; 181 181 } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { 182 182 ret = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, 183 - verdict >> NF_VERDICT_BITS); 183 + verdict >> NF_VERDICT_QBITS); 184 184 if (ret < 0) { 185 185 if (ret == -ECANCELED) 186 186 goto next_hook;
+1 -1
net/netfilter/nf_queue.c
··· 299 299 case NF_QUEUE: 300 300 err = __nf_queue(skb, elem, entry->pf, entry->hook, 301 301 entry->indev, entry->outdev, entry->okfn, 302 - verdict >> NF_VERDICT_BITS); 302 + verdict >> NF_VERDICT_QBITS); 303 303 if (err < 0) { 304 304 if (err == -ECANCELED) 305 305 goto next_hook;