diff options
author | Liping Zhang <zlpnobody@gmail.com> | 2017-03-08 09:54:18 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2017-03-13 08:30:28 -0400 |
commit | 10596608c4d62cb8c1c2b806debcbd32fe657e71 (patch) | |
tree | 1b78903a75011a45b7b647096b1319aedb475d11 /net | |
parent | fd89b23a4632d3cbdee398048497e026edadfb71 (diff) |
netfilter: nf_tables: fix mismatch in big-endian system
Currently, there are two different methods to store an u16 integer to
the u32 data register. For example:
u32 *dest = ®s->data[priv->dreg];
1. *dest = 0; *(u16 *) dest = val_u16;
2. *dest = val_u16;
For method 1, the u16 value will be stored like this, either in
big-endian or little-endian system:
0 15 31
+-+-+-+-+-+-+-+-+-+-+-+-+
| Value | 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+
For method 2, in little-endian system, the u16 value will be the same
as listed above. But in big-endian system, the u16 value will be stored
like this:
0 15 31
+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 | Value |
+-+-+-+-+-+-+-+-+-+-+-+-+
So later we use "memcmp(®s->data[priv->sreg], data, 2);" to do
compare in nft_cmp, nft_lookup expr ..., method 2 will get the wrong
result in big-endian system, as 0~15 bits will always be zero.
For the similar reason, when loading an u16 value from the u32 data
register, we should use "*(u16 *) sreg;" instead of "(u16)*sreg;",
the 2nd method will get the wrong value in the big-endian system.
So introduce some wrapper functions to store/load an u8 or u16
integer to/from the u32 data register, and use them in the right
place.
Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nft_masq_ipv4.c | 8 | ||||
-rw-r--r-- | net/ipv4/netfilter/nft_redir_ipv4.c | 8 | ||||
-rw-r--r-- | net/ipv6/netfilter/nft_masq_ipv6.c | 8 | ||||
-rw-r--r-- | net/ipv6/netfilter/nft_redir_ipv6.c | 8 | ||||
-rw-r--r-- | net/netfilter/nft_ct.c | 18 | ||||
-rw-r--r-- | net/netfilter/nft_meta.c | 40 | ||||
-rw-r--r-- | net/netfilter/nft_nat.c | 8 |
7 files changed, 51 insertions, 47 deletions
diff --git a/net/ipv4/netfilter/nft_masq_ipv4.c b/net/ipv4/netfilter/nft_masq_ipv4.c index a0ea8aad1bf1..f18677277119 100644 --- a/net/ipv4/netfilter/nft_masq_ipv4.c +++ b/net/ipv4/netfilter/nft_masq_ipv4.c | |||
@@ -26,10 +26,10 @@ static void nft_masq_ipv4_eval(const struct nft_expr *expr, | |||
26 | memset(&range, 0, sizeof(range)); | 26 | memset(&range, 0, sizeof(range)); |
27 | range.flags = priv->flags; | 27 | range.flags = priv->flags; |
28 | if (priv->sreg_proto_min) { | 28 | if (priv->sreg_proto_min) { |
29 | range.min_proto.all = | 29 | range.min_proto.all = (__force __be16)nft_reg_load16( |
30 | *(__be16 *)®s->data[priv->sreg_proto_min]; | 30 | ®s->data[priv->sreg_proto_min]); |
31 | range.max_proto.all = | 31 | range.max_proto.all = (__force __be16)nft_reg_load16( |
32 | *(__be16 *)®s->data[priv->sreg_proto_max]; | 32 | ®s->data[priv->sreg_proto_max]); |
33 | } | 33 | } |
34 | regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt), | 34 | regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt), |
35 | &range, nft_out(pkt)); | 35 | &range, nft_out(pkt)); |
diff --git a/net/ipv4/netfilter/nft_redir_ipv4.c b/net/ipv4/netfilter/nft_redir_ipv4.c index 1650ed23c15d..5120be1d3118 100644 --- a/net/ipv4/netfilter/nft_redir_ipv4.c +++ b/net/ipv4/netfilter/nft_redir_ipv4.c | |||
@@ -26,10 +26,10 @@ static void nft_redir_ipv4_eval(const struct nft_expr *expr, | |||
26 | 26 | ||
27 | memset(&mr, 0, sizeof(mr)); | 27 | memset(&mr, 0, sizeof(mr)); |
28 | if (priv->sreg_proto_min) { | 28 | if (priv->sreg_proto_min) { |
29 | mr.range[0].min.all = | 29 | mr.range[0].min.all = (__force __be16)nft_reg_load16( |
30 | *(__be16 *)®s->data[priv->sreg_proto_min]; | 30 | ®s->data[priv->sreg_proto_min]); |
31 | mr.range[0].max.all = | 31 | mr.range[0].max.all = (__force __be16)nft_reg_load16( |
32 | *(__be16 *)®s->data[priv->sreg_proto_max]; | 32 | ®s->data[priv->sreg_proto_max]); |
33 | mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | 33 | mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; |
34 | } | 34 | } |
35 | 35 | ||
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c index 6c5b5b1830a7..4146536e9c15 100644 --- a/net/ipv6/netfilter/nft_masq_ipv6.c +++ b/net/ipv6/netfilter/nft_masq_ipv6.c | |||
@@ -27,10 +27,10 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr, | |||
27 | memset(&range, 0, sizeof(range)); | 27 | memset(&range, 0, sizeof(range)); |
28 | range.flags = priv->flags; | 28 | range.flags = priv->flags; |
29 | if (priv->sreg_proto_min) { | 29 | if (priv->sreg_proto_min) { |
30 | range.min_proto.all = | 30 | range.min_proto.all = (__force __be16)nft_reg_load16( |
31 | *(__be16 *)®s->data[priv->sreg_proto_min]; | 31 | ®s->data[priv->sreg_proto_min]); |
32 | range.max_proto.all = | 32 | range.max_proto.all = (__force __be16)nft_reg_load16( |
33 | *(__be16 *)®s->data[priv->sreg_proto_max]; | 33 | ®s->data[priv->sreg_proto_max]); |
34 | } | 34 | } |
35 | regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, | 35 | regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, |
36 | nft_out(pkt)); | 36 | nft_out(pkt)); |
diff --git a/net/ipv6/netfilter/nft_redir_ipv6.c b/net/ipv6/netfilter/nft_redir_ipv6.c index f5ac080fc084..a27e424f690d 100644 --- a/net/ipv6/netfilter/nft_redir_ipv6.c +++ b/net/ipv6/netfilter/nft_redir_ipv6.c | |||
@@ -26,10 +26,10 @@ static void nft_redir_ipv6_eval(const struct nft_expr *expr, | |||
26 | 26 | ||
27 | memset(&range, 0, sizeof(range)); | 27 | memset(&range, 0, sizeof(range)); |
28 | if (priv->sreg_proto_min) { | 28 | if (priv->sreg_proto_min) { |
29 | range.min_proto.all = | 29 | range.min_proto.all = (__force __be16)nft_reg_load16( |
30 | *(__be16 *)®s->data[priv->sreg_proto_min], | 30 | ®s->data[priv->sreg_proto_min]); |
31 | range.max_proto.all = | 31 | range.max_proto.all = (__force __be16)nft_reg_load16( |
32 | *(__be16 *)®s->data[priv->sreg_proto_max], | 32 | ®s->data[priv->sreg_proto_max]); |
33 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | 33 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; |
34 | } | 34 | } |
35 | 35 | ||
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index bf548a7a71ec..91585b5e5307 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c | |||
@@ -83,7 +83,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, | |||
83 | 83 | ||
84 | switch (priv->key) { | 84 | switch (priv->key) { |
85 | case NFT_CT_DIRECTION: | 85 | case NFT_CT_DIRECTION: |
86 | *dest = CTINFO2DIR(ctinfo); | 86 | nft_reg_store8(dest, CTINFO2DIR(ctinfo)); |
87 | return; | 87 | return; |
88 | case NFT_CT_STATUS: | 88 | case NFT_CT_STATUS: |
89 | *dest = ct->status; | 89 | *dest = ct->status; |
@@ -151,20 +151,22 @@ static void nft_ct_get_eval(const struct nft_expr *expr, | |||
151 | return; | 151 | return; |
152 | } | 152 | } |
153 | case NFT_CT_L3PROTOCOL: | 153 | case NFT_CT_L3PROTOCOL: |
154 | *dest = nf_ct_l3num(ct); | 154 | nft_reg_store8(dest, nf_ct_l3num(ct)); |
155 | return; | 155 | return; |
156 | case NFT_CT_PROTOCOL: | 156 | case NFT_CT_PROTOCOL: |
157 | *dest = nf_ct_protonum(ct); | 157 | nft_reg_store8(dest, nf_ct_protonum(ct)); |
158 | return; | 158 | return; |
159 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 159 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
160 | case NFT_CT_ZONE: { | 160 | case NFT_CT_ZONE: { |
161 | const struct nf_conntrack_zone *zone = nf_ct_zone(ct); | 161 | const struct nf_conntrack_zone *zone = nf_ct_zone(ct); |
162 | u16 zoneid; | ||
162 | 163 | ||
163 | if (priv->dir < IP_CT_DIR_MAX) | 164 | if (priv->dir < IP_CT_DIR_MAX) |
164 | *dest = nf_ct_zone_id(zone, priv->dir); | 165 | zoneid = nf_ct_zone_id(zone, priv->dir); |
165 | else | 166 | else |
166 | *dest = zone->id; | 167 | zoneid = zone->id; |
167 | 168 | ||
169 | nft_reg_store16(dest, zoneid); | ||
168 | return; | 170 | return; |
169 | } | 171 | } |
170 | #endif | 172 | #endif |
@@ -183,10 +185,10 @@ static void nft_ct_get_eval(const struct nft_expr *expr, | |||
183 | nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); | 185 | nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); |
184 | return; | 186 | return; |
185 | case NFT_CT_PROTO_SRC: | 187 | case NFT_CT_PROTO_SRC: |
186 | *dest = (__force __u16)tuple->src.u.all; | 188 | nft_reg_store16(dest, (__force u16)tuple->src.u.all); |
187 | return; | 189 | return; |
188 | case NFT_CT_PROTO_DST: | 190 | case NFT_CT_PROTO_DST: |
189 | *dest = (__force __u16)tuple->dst.u.all; | 191 | nft_reg_store16(dest, (__force u16)tuple->dst.u.all); |
190 | return; | 192 | return; |
191 | default: | 193 | default: |
192 | break; | 194 | break; |
@@ -205,7 +207,7 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr, | |||
205 | const struct nft_ct *priv = nft_expr_priv(expr); | 207 | const struct nft_ct *priv = nft_expr_priv(expr); |
206 | struct sk_buff *skb = pkt->skb; | 208 | struct sk_buff *skb = pkt->skb; |
207 | enum ip_conntrack_info ctinfo; | 209 | enum ip_conntrack_info ctinfo; |
208 | u16 value = regs->data[priv->sreg]; | 210 | u16 value = nft_reg_load16(®s->data[priv->sreg]); |
209 | struct nf_conn *ct; | 211 | struct nf_conn *ct; |
210 | 212 | ||
211 | ct = nf_ct_get(skb, &ctinfo); | 213 | ct = nf_ct_get(skb, &ctinfo); |
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index e1f5ca9b423b..7b60e01f38ff 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c | |||
@@ -45,16 +45,15 @@ void nft_meta_get_eval(const struct nft_expr *expr, | |||
45 | *dest = skb->len; | 45 | *dest = skb->len; |
46 | break; | 46 | break; |
47 | case NFT_META_PROTOCOL: | 47 | case NFT_META_PROTOCOL: |
48 | *dest = 0; | 48 | nft_reg_store16(dest, (__force u16)skb->protocol); |
49 | *(__be16 *)dest = skb->protocol; | ||
50 | break; | 49 | break; |
51 | case NFT_META_NFPROTO: | 50 | case NFT_META_NFPROTO: |
52 | *dest = nft_pf(pkt); | 51 | nft_reg_store8(dest, nft_pf(pkt)); |
53 | break; | 52 | break; |
54 | case NFT_META_L4PROTO: | 53 | case NFT_META_L4PROTO: |
55 | if (!pkt->tprot_set) | 54 | if (!pkt->tprot_set) |
56 | goto err; | 55 | goto err; |
57 | *dest = pkt->tprot; | 56 | nft_reg_store8(dest, pkt->tprot); |
58 | break; | 57 | break; |
59 | case NFT_META_PRIORITY: | 58 | case NFT_META_PRIORITY: |
60 | *dest = skb->priority; | 59 | *dest = skb->priority; |
@@ -85,14 +84,12 @@ void nft_meta_get_eval(const struct nft_expr *expr, | |||
85 | case NFT_META_IIFTYPE: | 84 | case NFT_META_IIFTYPE: |
86 | if (in == NULL) | 85 | if (in == NULL) |
87 | goto err; | 86 | goto err; |
88 | *dest = 0; | 87 | nft_reg_store16(dest, in->type); |
89 | *(u16 *)dest = in->type; | ||
90 | break; | 88 | break; |
91 | case NFT_META_OIFTYPE: | 89 | case NFT_META_OIFTYPE: |
92 | if (out == NULL) | 90 | if (out == NULL) |
93 | goto err; | 91 | goto err; |
94 | *dest = 0; | 92 | nft_reg_store16(dest, out->type); |
95 | *(u16 *)dest = out->type; | ||
96 | break; | 93 | break; |
97 | case NFT_META_SKUID: | 94 | case NFT_META_SKUID: |
98 | sk = skb_to_full_sk(skb); | 95 | sk = skb_to_full_sk(skb); |
@@ -142,19 +139,19 @@ void nft_meta_get_eval(const struct nft_expr *expr, | |||
142 | #endif | 139 | #endif |
143 | case NFT_META_PKTTYPE: | 140 | case NFT_META_PKTTYPE: |
144 | if (skb->pkt_type != PACKET_LOOPBACK) { | 141 | if (skb->pkt_type != PACKET_LOOPBACK) { |
145 | *dest = skb->pkt_type; | 142 | nft_reg_store8(dest, skb->pkt_type); |
146 | break; | 143 | break; |
147 | } | 144 | } |
148 | 145 | ||
149 | switch (nft_pf(pkt)) { | 146 | switch (nft_pf(pkt)) { |
150 | case NFPROTO_IPV4: | 147 | case NFPROTO_IPV4: |
151 | if (ipv4_is_multicast(ip_hdr(skb)->daddr)) | 148 | if (ipv4_is_multicast(ip_hdr(skb)->daddr)) |
152 | *dest = PACKET_MULTICAST; | 149 | nft_reg_store8(dest, PACKET_MULTICAST); |
153 | else | 150 | else |
154 | *dest = PACKET_BROADCAST; | 151 | nft_reg_store8(dest, PACKET_BROADCAST); |
155 | break; | 152 | break; |
156 | case NFPROTO_IPV6: | 153 | case NFPROTO_IPV6: |
157 | *dest = PACKET_MULTICAST; | 154 | nft_reg_store8(dest, PACKET_MULTICAST); |
158 | break; | 155 | break; |
159 | case NFPROTO_NETDEV: | 156 | case NFPROTO_NETDEV: |
160 | switch (skb->protocol) { | 157 | switch (skb->protocol) { |
@@ -168,14 +165,14 @@ void nft_meta_get_eval(const struct nft_expr *expr, | |||
168 | goto err; | 165 | goto err; |
169 | 166 | ||
170 | if (ipv4_is_multicast(iph->daddr)) | 167 | if (ipv4_is_multicast(iph->daddr)) |
171 | *dest = PACKET_MULTICAST; | 168 | nft_reg_store8(dest, PACKET_MULTICAST); |
172 | else | 169 | else |
173 | *dest = PACKET_BROADCAST; | 170 | nft_reg_store8(dest, PACKET_BROADCAST); |
174 | 171 | ||
175 | break; | 172 | break; |
176 | } | 173 | } |
177 | case htons(ETH_P_IPV6): | 174 | case htons(ETH_P_IPV6): |
178 | *dest = PACKET_MULTICAST; | 175 | nft_reg_store8(dest, PACKET_MULTICAST); |
179 | break; | 176 | break; |
180 | default: | 177 | default: |
181 | WARN_ON_ONCE(1); | 178 | WARN_ON_ONCE(1); |
@@ -230,7 +227,9 @@ void nft_meta_set_eval(const struct nft_expr *expr, | |||
230 | { | 227 | { |
231 | const struct nft_meta *meta = nft_expr_priv(expr); | 228 | const struct nft_meta *meta = nft_expr_priv(expr); |
232 | struct sk_buff *skb = pkt->skb; | 229 | struct sk_buff *skb = pkt->skb; |
233 | u32 value = regs->data[meta->sreg]; | 230 | u32 *sreg = ®s->data[meta->sreg]; |
231 | u32 value = *sreg; | ||
232 | u8 pkt_type; | ||
234 | 233 | ||
235 | switch (meta->key) { | 234 | switch (meta->key) { |
236 | case NFT_META_MARK: | 235 | case NFT_META_MARK: |
@@ -240,9 +239,12 @@ void nft_meta_set_eval(const struct nft_expr *expr, | |||
240 | skb->priority = value; | 239 | skb->priority = value; |
241 | break; | 240 | break; |
242 | case NFT_META_PKTTYPE: | 241 | case NFT_META_PKTTYPE: |
243 | if (skb->pkt_type != value && | 242 | pkt_type = nft_reg_load8(sreg); |
244 | skb_pkt_type_ok(value) && skb_pkt_type_ok(skb->pkt_type)) | 243 | |
245 | skb->pkt_type = value; | 244 | if (skb->pkt_type != pkt_type && |
245 | skb_pkt_type_ok(pkt_type) && | ||
246 | skb_pkt_type_ok(skb->pkt_type)) | ||
247 | skb->pkt_type = pkt_type; | ||
246 | break; | 248 | break; |
247 | case NFT_META_NFTRACE: | 249 | case NFT_META_NFTRACE: |
248 | skb->nf_trace = !!value; | 250 | skb->nf_trace = !!value; |
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index 19a7bf3236f9..439e0bd152a0 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c | |||
@@ -65,10 +65,10 @@ static void nft_nat_eval(const struct nft_expr *expr, | |||
65 | } | 65 | } |
66 | 66 | ||
67 | if (priv->sreg_proto_min) { | 67 | if (priv->sreg_proto_min) { |
68 | range.min_proto.all = | 68 | range.min_proto.all = (__force __be16)nft_reg_load16( |
69 | *(__be16 *)®s->data[priv->sreg_proto_min]; | 69 | ®s->data[priv->sreg_proto_min]); |
70 | range.max_proto.all = | 70 | range.max_proto.all = (__force __be16)nft_reg_load16( |
71 | *(__be16 *)®s->data[priv->sreg_proto_max]; | 71 | ®s->data[priv->sreg_proto_max]); |
72 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; | 72 | range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; |
73 | } | 73 | } |
74 | 74 | ||