summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLiping Zhang <zlpnobody@gmail.com>2017-03-08 09:54:18 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2017-03-13 08:30:28 -0400
commit10596608c4d62cb8c1c2b806debcbd32fe657e71 (patch)
tree1b78903a75011a45b7b647096b1319aedb475d11 /net
parentfd89b23a4632d3cbdee398048497e026edadfb71 (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 = &regs->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(&regs->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.c8
-rw-r--r--net/ipv4/netfilter/nft_redir_ipv4.c8
-rw-r--r--net/ipv6/netfilter/nft_masq_ipv6.c8
-rw-r--r--net/ipv6/netfilter/nft_redir_ipv6.c8
-rw-r--r--net/netfilter/nft_ct.c18
-rw-r--r--net/netfilter/nft_meta.c40
-rw-r--r--net/netfilter/nft_nat.c8
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 *)&regs->data[priv->sreg_proto_min]; 30 &regs->data[priv->sreg_proto_min]);
31 range.max_proto.all = 31 range.max_proto.all = (__force __be16)nft_reg_load16(
32 *(__be16 *)&regs->data[priv->sreg_proto_max]; 32 &regs->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 *)&regs->data[priv->sreg_proto_min]; 30 &regs->data[priv->sreg_proto_min]);
31 mr.range[0].max.all = 31 mr.range[0].max.all = (__force __be16)nft_reg_load16(
32 *(__be16 *)&regs->data[priv->sreg_proto_max]; 32 &regs->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 *)&regs->data[priv->sreg_proto_min]; 31 &regs->data[priv->sreg_proto_min]);
32 range.max_proto.all = 32 range.max_proto.all = (__force __be16)nft_reg_load16(
33 *(__be16 *)&regs->data[priv->sreg_proto_max]; 33 &regs->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 *)&regs->data[priv->sreg_proto_min], 30 &regs->data[priv->sreg_proto_min]);
31 range.max_proto.all = 31 range.max_proto.all = (__force __be16)nft_reg_load16(
32 *(__be16 *)&regs->data[priv->sreg_proto_max], 32 &regs->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(&regs->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 = &regs->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 *)&regs->data[priv->sreg_proto_min]; 69 &regs->data[priv->sreg_proto_min]);
70 range.max_proto.all = 70 range.max_proto.all = (__force __be16)nft_reg_load16(
71 *(__be16 *)&regs->data[priv->sreg_proto_max]; 71 &regs->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