* [PATCH nf] netfilter: nft_exthdr: fix endianness of tcp option cast
@ 2020-03-29 12:19 Sergey Marinkevich
2020-03-29 13:44 ` Florian Westphal
2020-04-02 1:12 ` kbuild test robot
0 siblings, 2 replies; 3+ messages in thread
From: Sergey Marinkevich @ 2020-03-29 12:19 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Jozsef Kadlecsik, Florian Westphal, David S. Miller,
Jakub Kicinski, netfilter-devel, netdev
I got a problem on MIPS with Big-Endian is turned on: every time when
NF trying to change TCP MSS it returns because of new.v16 was greater
than old.v16. But real MSS was 1460 and my rule was like this:
add rule table chain tcp option maxseg size set 1400
And 1400 is lesser that 1460, not greater.
Later I founded that main causer is cast from u32 to __be16.
Debugging:
In example MSS = 1400(HEX: 0x578). Here is representation of each byte
like it is in memory by addresses from left to right(e.g. [0x0 0x1 0x2
0x3]). LE — Little-Endian system, BE — Big-Endian, left column is type.
LE BE
u32: [78 05 00 00] [00 00 05 78]
As you can see, u32 representation will be casted to u16 from different
half of 4-byte address range. But actually nf_tables uses registers and
store data of various size. Actually TCP MSS stored in 2 bytes. But
registers are still u32 in definition:
struct nft_regs {
union {
u32 data[20];
struct nft_verdict verdict;
};
};
So, access like regs->data[priv->sreg] exactly u32. So, according to
table presents above, per-byte representation of stored TCP MSS in
register will be:
LE BE
(u32)regs->data[]: [78 05 00 00] [05 78 00 00]
^^ ^^
We see that register uses just half of u32 and other 2 bytes may be
used for some another data. But in nft_exthdr_tcp_set_eval() it casted
just like u32 -> __be16:
new.v16 = src
But u32 overfill __be16, so it get 2 low bytes. For clarity draw
one more table(<xx xx> means that bytes will be used for cast).
LE BE
u32: [<78 05> 00 00] [00 00 <05 78>]
(u32)regs->data[]: [<78 05> 00 00] [05 78 <00 00>]
As you can see, for Little-Endian nothing changes, but for Big-endian we
take the wrong half. In my case there is some other data instead of
zeros, so new MSS was wrongly greater.
For shooting this bug I used solution for ports ranges. Applying of this
patch does not affect Little-Endian systems.
Signed-off-by: Sergey Marinkevich <sergey.marinkevich@eltex-co.ru>
---
net/netfilter/nft_exthdr.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
index a5e8469859e3..07782836fad6 100644
--- a/net/netfilter/nft_exthdr.c
+++ b/net/netfilter/nft_exthdr.c
@@ -228,7 +228,6 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
unsigned int i, optl, tcphdr_len, offset;
struct tcphdr *tcph;
u8 *opt;
- u32 src;
tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
if (!tcph)
@@ -237,7 +236,6 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
opt = (u8 *)tcph;
for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
union {
- u8 octet;
__be16 v16;
__be32 v32;
} old, new;
@@ -259,13 +257,13 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
if (!tcph)
return;
- src = regs->data[priv->sreg];
offset = i + priv->offset;
switch (priv->len) {
case 2:
old.v16 = get_unaligned((u16 *)(opt + offset));
- new.v16 = src;
+ new.v16 = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg]);
switch (priv->type) {
case TCPOPT_MSS:
@@ -283,7 +281,7 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
old.v16, new.v16, false);
break;
case 4:
- new.v32 = src;
+ new.v32 = regs->data[priv->sreg];
old.v32 = get_unaligned((u32 *)(opt + offset));
if (old.v32 == new.v32)
--
2.21.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH nf] netfilter: nft_exthdr: fix endianness of tcp option cast
2020-03-29 12:19 [PATCH nf] netfilter: nft_exthdr: fix endianness of tcp option cast Sergey Marinkevich
@ 2020-03-29 13:44 ` Florian Westphal
2020-04-02 1:12 ` kbuild test robot
1 sibling, 0 replies; 3+ messages in thread
From: Florian Westphal @ 2020-03-29 13:44 UTC (permalink / raw)
To: Sergey Marinkevich
Cc: Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S. Miller, Jakub Kicinski, netfilter-devel, netdev
Sergey Marinkevich <sergey.marinkevich@eltex-co.ru> wrote:
> I got a problem on MIPS with Big-Endian is turned on: every time when
> NF trying to change TCP MSS it returns because of new.v16 was greater
> than old.v16. But real MSS was 1460 and my rule was like this:
>
> add rule table chain tcp option maxseg size set 1400
>
> And 1400 is lesser that 1460, not greater.
>
> Later I founded that main causer is cast from u32 to __be16.
LGTM.
Acked-by: Florian Westphal <fw@strlen.de>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH nf] netfilter: nft_exthdr: fix endianness of tcp option cast
2020-03-29 12:19 [PATCH nf] netfilter: nft_exthdr: fix endianness of tcp option cast Sergey Marinkevich
2020-03-29 13:44 ` Florian Westphal
@ 2020-04-02 1:12 ` kbuild test robot
1 sibling, 0 replies; 3+ messages in thread
From: kbuild test robot @ 2020-04-02 1:12 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 8491 bytes --]
Hi Sergey,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on nf/master]
[also build test WARNING on nf-next/master ipvs/master v5.6 next-20200327]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Sergey-Marinkevich/netfilter-nft_exthdr-fix-endianness-of-tcp-option-cast/20200329-215834
base: https://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git master
reproduce:
# apt-get install sparse
# sparse version: v0.6.1-187-gbff9b106-dirty
make ARCH=x86_64 allmodconfig
make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'
:::::: branch date: 11 hours ago
:::::: commit date: 11 hours ago
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
net/netfilter/nft_exthdr.c:264:33: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __be16 [usertype] v16 @@ got 16 [usertype] v16 @@
net/netfilter/nft_exthdr.c:264:33: sparse: expected restricted __be16 [usertype] v16
net/netfilter/nft_exthdr.c:264:33: sparse: got unsigned short
>> net/netfilter/nft_exthdr.c:284:33: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __be32 [assigned] [usertype] v32 @@ got [usertype] v32 @@
>> net/netfilter/nft_exthdr.c:284:33: sparse: expected restricted __be32 [assigned] [usertype] v32
net/netfilter/nft_exthdr.c:284:33: sparse: got unsigned int
net/netfilter/nft_exthdr.c:285:33: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __be32 [usertype] v32 @@ got [usertype] v32 @@
net/netfilter/nft_exthdr.c:285:33: sparse: expected restricted __be32 [usertype] v32
net/netfilter/nft_exthdr.c:285:33: sparse: got unsigned int
# https://github.com/0day-ci/linux/commit/d9b9ce8e0720a559cb92e044b3721f9acc51990b
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout d9b9ce8e0720a559cb92e044b3721f9acc51990b
vim +284 net/netfilter/nft_exthdr.c
935b7f64301887 Manuel Messner 2017-02-07 221
99d1712bc41c7c Florian Westphal 2017-08-08 222 static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
99d1712bc41c7c Florian Westphal 2017-08-08 223 struct nft_regs *regs,
99d1712bc41c7c Florian Westphal 2017-08-08 224 const struct nft_pktinfo *pkt)
99d1712bc41c7c Florian Westphal 2017-08-08 225 {
99d1712bc41c7c Florian Westphal 2017-08-08 226 u8 buff[sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE];
99d1712bc41c7c Florian Westphal 2017-08-08 227 struct nft_exthdr *priv = nft_expr_priv(expr);
99d1712bc41c7c Florian Westphal 2017-08-08 228 unsigned int i, optl, tcphdr_len, offset;
99d1712bc41c7c Florian Westphal 2017-08-08 229 struct tcphdr *tcph;
99d1712bc41c7c Florian Westphal 2017-08-08 230 u8 *opt;
99d1712bc41c7c Florian Westphal 2017-08-08 231
99d1712bc41c7c Florian Westphal 2017-08-08 232 tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
99d1712bc41c7c Florian Westphal 2017-08-08 233 if (!tcph)
99d1712bc41c7c Florian Westphal 2017-08-08 234 return;
99d1712bc41c7c Florian Westphal 2017-08-08 235
99d1712bc41c7c Florian Westphal 2017-08-08 236 opt = (u8 *)tcph;
99d1712bc41c7c Florian Westphal 2017-08-08 237 for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
99d1712bc41c7c Florian Westphal 2017-08-08 238 union {
99d1712bc41c7c Florian Westphal 2017-08-08 239 __be16 v16;
99d1712bc41c7c Florian Westphal 2017-08-08 240 __be32 v32;
99d1712bc41c7c Florian Westphal 2017-08-08 241 } old, new;
99d1712bc41c7c Florian Westphal 2017-08-08 242
99d1712bc41c7c Florian Westphal 2017-08-08 243 optl = optlen(opt, i);
99d1712bc41c7c Florian Westphal 2017-08-08 244
99d1712bc41c7c Florian Westphal 2017-08-08 245 if (priv->type != opt[i])
99d1712bc41c7c Florian Westphal 2017-08-08 246 continue;
99d1712bc41c7c Florian Westphal 2017-08-08 247
99d1712bc41c7c Florian Westphal 2017-08-08 248 if (i + optl > tcphdr_len || priv->len + priv->offset > optl)
99d1712bc41c7c Florian Westphal 2017-08-08 249 return;
99d1712bc41c7c Florian Westphal 2017-08-08 250
7418ee4c8810e4 Florian Westphal 2019-05-23 251 if (skb_ensure_writable(pkt->skb,
7418ee4c8810e4 Florian Westphal 2019-05-23 252 pkt->xt.thoff + i + priv->len))
99d1712bc41c7c Florian Westphal 2017-08-08 253 return;
99d1712bc41c7c Florian Westphal 2017-08-08 254
99d1712bc41c7c Florian Westphal 2017-08-08 255 tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
99d1712bc41c7c Florian Westphal 2017-08-08 256 &tcphdr_len);
99d1712bc41c7c Florian Westphal 2017-08-08 257 if (!tcph)
99d1712bc41c7c Florian Westphal 2017-08-08 258 return;
99d1712bc41c7c Florian Westphal 2017-08-08 259
99d1712bc41c7c Florian Westphal 2017-08-08 260 offset = i + priv->offset;
99d1712bc41c7c Florian Westphal 2017-08-08 261
99d1712bc41c7c Florian Westphal 2017-08-08 262 switch (priv->len) {
99d1712bc41c7c Florian Westphal 2017-08-08 263 case 2:
99d1712bc41c7c Florian Westphal 2017-08-08 264 old.v16 = get_unaligned((u16 *)(opt + offset));
d9b9ce8e0720a5 Sergey Marinkevich 2020-03-29 265 new.v16 = (__force __be16)nft_reg_load16(
d9b9ce8e0720a5 Sergey Marinkevich 2020-03-29 266 ®s->data[priv->sreg]);
99d1712bc41c7c Florian Westphal 2017-08-08 267
99d1712bc41c7c Florian Westphal 2017-08-08 268 switch (priv->type) {
99d1712bc41c7c Florian Westphal 2017-08-08 269 case TCPOPT_MSS:
99d1712bc41c7c Florian Westphal 2017-08-08 270 /* increase can cause connection to stall */
99d1712bc41c7c Florian Westphal 2017-08-08 271 if (ntohs(old.v16) <= ntohs(new.v16))
99d1712bc41c7c Florian Westphal 2017-08-08 272 return;
99d1712bc41c7c Florian Westphal 2017-08-08 273 break;
99d1712bc41c7c Florian Westphal 2017-08-08 274 }
99d1712bc41c7c Florian Westphal 2017-08-08 275
99d1712bc41c7c Florian Westphal 2017-08-08 276 if (old.v16 == new.v16)
99d1712bc41c7c Florian Westphal 2017-08-08 277 return;
99d1712bc41c7c Florian Westphal 2017-08-08 278
99d1712bc41c7c Florian Westphal 2017-08-08 279 put_unaligned(new.v16, (u16*)(opt + offset));
99d1712bc41c7c Florian Westphal 2017-08-08 280 inet_proto_csum_replace2(&tcph->check, pkt->skb,
99d1712bc41c7c Florian Westphal 2017-08-08 281 old.v16, new.v16, false);
99d1712bc41c7c Florian Westphal 2017-08-08 282 break;
99d1712bc41c7c Florian Westphal 2017-08-08 283 case 4:
d9b9ce8e0720a5 Sergey Marinkevich 2020-03-29 @284 new.v32 = regs->data[priv->sreg];
99d1712bc41c7c Florian Westphal 2017-08-08 285 old.v32 = get_unaligned((u32 *)(opt + offset));
99d1712bc41c7c Florian Westphal 2017-08-08 286
99d1712bc41c7c Florian Westphal 2017-08-08 287 if (old.v32 == new.v32)
99d1712bc41c7c Florian Westphal 2017-08-08 288 return;
99d1712bc41c7c Florian Westphal 2017-08-08 289
99d1712bc41c7c Florian Westphal 2017-08-08 290 put_unaligned(new.v32, (u32*)(opt + offset));
99d1712bc41c7c Florian Westphal 2017-08-08 291 inet_proto_csum_replace4(&tcph->check, pkt->skb,
99d1712bc41c7c Florian Westphal 2017-08-08 292 old.v32, new.v32, false);
99d1712bc41c7c Florian Westphal 2017-08-08 293 break;
99d1712bc41c7c Florian Westphal 2017-08-08 294 default:
99d1712bc41c7c Florian Westphal 2017-08-08 295 WARN_ON_ONCE(1);
99d1712bc41c7c Florian Westphal 2017-08-08 296 break;
99d1712bc41c7c Florian Westphal 2017-08-08 297 }
99d1712bc41c7c Florian Westphal 2017-08-08 298
99d1712bc41c7c Florian Westphal 2017-08-08 299 return;
99d1712bc41c7c Florian Westphal 2017-08-08 300 }
99d1712bc41c7c Florian Westphal 2017-08-08 301 }
99d1712bc41c7c Florian Westphal 2017-08-08 302
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-04-02 1:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-29 12:19 [PATCH nf] netfilter: nft_exthdr: fix endianness of tcp option cast Sergey Marinkevich
2020-03-29 13:44 ` Florian Westphal
2020-04-02 1:12 ` kbuild test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.