5e56d0dc491af6af0a286b09ed8d5edf8e946528
[oweals/openwrt.git] /
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Sat, 30 Dec 2017 22:41:46 +0100
3 Subject: [PATCH] netfilter: remove defensive check on malformed packets from
4  raw sockets
5
6 Users cannot forge malformed IPv4/IPv6 headers via raw sockets that they
7 can inject into the stack. Specifically, not for IPv4 since 55888dfb6ba7
8 ("AF_RAW: Augment raw_send_hdrinc to expand skb to fit iphdr->ihl
9 (v2)"). IPv6 raw sockets also ensure that packets have a well-formed
10 IPv6 header available in the skbuff.
11
12 At quick glance, br_netfilter also validates layer 3 headers and it
13 drops malformed both IPv4 and IPv6 packets.
14
15 Therefore, let's remove this defensive check all over the place.
16
17 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
18 ---
19
20 --- a/net/ipv4/netfilter/iptable_filter.c
21 +++ b/net/ipv4/netfilter/iptable_filter.c
22 @@ -38,12 +38,6 @@ static unsigned int
23  iptable_filter_hook(void *priv, struct sk_buff *skb,
24                     const struct nf_hook_state *state)
25  {
26 -       if (state->hook == NF_INET_LOCAL_OUT &&
27 -           (skb->len < sizeof(struct iphdr) ||
28 -            ip_hdrlen(skb) < sizeof(struct iphdr)))
29 -               /* root is playing with raw sockets. */
30 -               return NF_ACCEPT;
31 -
32         return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
33  }
34  
35 --- a/net/ipv4/netfilter/iptable_mangle.c
36 +++ b/net/ipv4/netfilter/iptable_mangle.c
37 @@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, cons
38         u_int32_t mark;
39         int err;
40  
41 -       /* root is playing with raw sockets. */
42 -       if (skb->len < sizeof(struct iphdr) ||
43 -           ip_hdrlen(skb) < sizeof(struct iphdr))
44 -               return NF_ACCEPT;
45 -
46         /* Save things which could affect route */
47         mark = skb->mark;
48         iph = ip_hdr(skb);
49 --- a/net/ipv4/netfilter/iptable_raw.c
50 +++ b/net/ipv4/netfilter/iptable_raw.c
51 @@ -26,12 +26,6 @@ static unsigned int
52  iptable_raw_hook(void *priv, struct sk_buff *skb,
53                  const struct nf_hook_state *state)
54  {
55 -       if (state->hook == NF_INET_LOCAL_OUT &&
56 -           (skb->len < sizeof(struct iphdr) ||
57 -            ip_hdrlen(skb) < sizeof(struct iphdr)))
58 -               /* root is playing with raw sockets. */
59 -               return NF_ACCEPT;
60 -
61         return ipt_do_table(skb, state, state->net->ipv4.iptable_raw);
62  }
63  
64 --- a/net/ipv4/netfilter/iptable_security.c
65 +++ b/net/ipv4/netfilter/iptable_security.c
66 @@ -43,12 +43,6 @@ static unsigned int
67  iptable_security_hook(void *priv, struct sk_buff *skb,
68                       const struct nf_hook_state *state)
69  {
70 -       if (state->hook == NF_INET_LOCAL_OUT &&
71 -           (skb->len < sizeof(struct iphdr) ||
72 -            ip_hdrlen(skb) < sizeof(struct iphdr)))
73 -               /* Somebody is playing with raw sockets. */
74 -               return NF_ACCEPT;
75 -
76         return ipt_do_table(skb, state, state->net->ipv4.iptable_security);
77  }
78  
79 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
80 +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
81 @@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local
82                                          struct sk_buff *skb,
83                                          const struct nf_hook_state *state)
84  {
85 -       /* root is playing with raw sockets. */
86 -       if (skb->len < sizeof(struct iphdr) ||
87 -           ip_hdrlen(skb) < sizeof(struct iphdr))
88 -               return NF_ACCEPT;
89 -
90         if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
91                 enum ip_conntrack_info ctinfo;
92                 struct nf_conn *tmpl;
93 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
94 +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
95 @@ -355,11 +355,6 @@ nf_nat_ipv4_out(void *priv, struct sk_bu
96  #endif
97         unsigned int ret;
98  
99 -       /* root is playing with raw sockets. */
100 -       if (skb->len < sizeof(struct iphdr) ||
101 -           ip_hdrlen(skb) < sizeof(struct iphdr))
102 -               return NF_ACCEPT;
103 -
104         ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
105  #ifdef CONFIG_XFRM
106         if (ret != NF_DROP && ret != NF_STOLEN &&
107 @@ -395,11 +390,6 @@ nf_nat_ipv4_local_fn(void *priv, struct
108         unsigned int ret;
109         int err;
110  
111 -       /* root is playing with raw sockets. */
112 -       if (skb->len < sizeof(struct iphdr) ||
113 -           ip_hdrlen(skb) < sizeof(struct iphdr))
114 -               return NF_ACCEPT;
115 -
116         ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
117         if (ret != NF_DROP && ret != NF_STOLEN &&
118             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
119 --- a/net/ipv4/netfilter/nf_tables_ipv4.c
120 +++ b/net/ipv4/netfilter/nf_tables_ipv4.c
121 @@ -30,21 +30,6 @@ static unsigned int nft_do_chain_ipv4(vo
122         return nft_do_chain(&pkt, priv);
123  }
124  
125 -static unsigned int nft_ipv4_output(void *priv,
126 -                                   struct sk_buff *skb,
127 -                                   const struct nf_hook_state *state)
128 -{
129 -       if (unlikely(skb->len < sizeof(struct iphdr) ||
130 -                    ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
131 -               if (net_ratelimit())
132 -                       pr_info("nf_tables_ipv4: ignoring short SOCK_RAW "
133 -                               "packet\n");
134 -               return NF_ACCEPT;
135 -       }
136 -
137 -       return nft_do_chain_ipv4(priv, skb, state);
138 -}
139 -
140  static struct nft_af_info nft_af_ipv4 __read_mostly = {
141         .family         = NFPROTO_IPV4,
142         .nhooks         = NF_INET_NUMHOOKS,
143 @@ -91,7 +76,7 @@ static const struct nf_chain_type filter
144                           (1 << NF_INET_POST_ROUTING),
145         .hooks          = {
146                 [NF_INET_LOCAL_IN]      = nft_do_chain_ipv4,
147 -               [NF_INET_LOCAL_OUT]     = nft_ipv4_output,
148 +               [NF_INET_LOCAL_OUT]     = nft_do_chain_ipv4,
149                 [NF_INET_FORWARD]       = nft_do_chain_ipv4,
150                 [NF_INET_PRE_ROUTING]   = nft_do_chain_ipv4,
151                 [NF_INET_POST_ROUTING]  = nft_do_chain_ipv4,
152 --- a/net/ipv4/netfilter/nft_chain_route_ipv4.c
153 +++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c
154 @@ -33,11 +33,6 @@ static unsigned int nf_route_table_hook(
155         const struct iphdr *iph;
156         int err;
157  
158 -       /* root is playing with raw sockets. */
159 -       if (skb->len < sizeof(struct iphdr) ||
160 -           ip_hdrlen(skb) < sizeof(struct iphdr))
161 -               return NF_ACCEPT;
162 -
163         nft_set_pktinfo(&pkt, skb, state);
164         nft_set_pktinfo_ipv4(&pkt, skb);
165  
166 --- a/net/ipv6/netfilter/ip6table_mangle.c
167 +++ b/net/ipv6/netfilter/ip6table_mangle.c
168 @@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, con
169         u_int8_t hop_limit;
170         u_int32_t flowlabel, mark;
171         int err;
172 -#if 0
173 -       /* root is playing with raw sockets. */
174 -       if (skb->len < sizeof(struct iphdr) ||
175 -           ip_hdrlen(skb) < sizeof(struct iphdr)) {
176 -               net_warn_ratelimited("ip6t_hook: happy cracking\n");
177 -               return NF_ACCEPT;
178 -       }
179 -#endif
180  
181         /* save source/dest address, mark, hoplimit, flowlabel, priority,  */
182         memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
183 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
184 +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
185 @@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local
186                                          struct sk_buff *skb,
187                                          const struct nf_hook_state *state)
188  {
189 -       /* root is playing with raw sockets. */
190 -       if (skb->len < sizeof(struct ipv6hdr)) {
191 -               net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
192 -               return NF_ACCEPT;
193 -       }
194         return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
195  }
196  
197 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
198 +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
199 @@ -372,10 +372,6 @@ nf_nat_ipv6_out(void *priv, struct sk_bu
200  #endif
201         unsigned int ret;
202  
203 -       /* root is playing with raw sockets. */
204 -       if (skb->len < sizeof(struct ipv6hdr))
205 -               return NF_ACCEPT;
206 -
207         ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
208  #ifdef CONFIG_XFRM
209         if (ret != NF_DROP && ret != NF_STOLEN &&
210 @@ -411,10 +407,6 @@ nf_nat_ipv6_local_fn(void *priv, struct
211         unsigned int ret;
212         int err;
213  
214 -       /* root is playing with raw sockets. */
215 -       if (skb->len < sizeof(struct ipv6hdr))
216 -               return NF_ACCEPT;
217 -
218         ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
219         if (ret != NF_DROP && ret != NF_STOLEN &&
220             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
221 --- a/net/ipv6/netfilter/nf_tables_ipv6.c
222 +++ b/net/ipv6/netfilter/nf_tables_ipv6.c
223 @@ -28,20 +28,6 @@ static unsigned int nft_do_chain_ipv6(vo
224         return nft_do_chain(&pkt, priv);
225  }
226  
227 -static unsigned int nft_ipv6_output(void *priv,
228 -                                   struct sk_buff *skb,
229 -                                   const struct nf_hook_state *state)
230 -{
231 -       if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
232 -               if (net_ratelimit())
233 -                       pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
234 -                               "packet\n");
235 -               return NF_ACCEPT;
236 -       }
237 -
238 -       return nft_do_chain_ipv6(priv, skb, state);
239 -}
240 -
241  static struct nft_af_info nft_af_ipv6 __read_mostly = {
242         .family         = NFPROTO_IPV6,
243         .nhooks         = NF_INET_NUMHOOKS,
244 @@ -88,7 +74,7 @@ static const struct nf_chain_type filter
245                           (1 << NF_INET_POST_ROUTING),
246         .hooks          = {
247                 [NF_INET_LOCAL_IN]      = nft_do_chain_ipv6,
248 -               [NF_INET_LOCAL_OUT]     = nft_ipv6_output,
249 +               [NF_INET_LOCAL_OUT]     = nft_do_chain_ipv6,
250                 [NF_INET_FORWARD]       = nft_do_chain_ipv6,
251                 [NF_INET_PRE_ROUTING]   = nft_do_chain_ipv6,
252                 [NF_INET_POST_ROUTING]  = nft_do_chain_ipv6,
253 --- a/net/netfilter/nf_tables_inet.c
254 +++ b/net/netfilter/nf_tables_inet.c
255 @@ -38,38 +38,6 @@ static unsigned int nft_do_chain_inet(vo
256         return nft_do_chain(&pkt, priv);
257  }
258  
259 -static unsigned int nft_inet_output(void *priv, struct sk_buff *skb,
260 -                                   const struct nf_hook_state *state)
261 -{
262 -       struct nft_pktinfo pkt;
263 -
264 -       nft_set_pktinfo(&pkt, skb, state);
265 -
266 -       switch (state->pf) {
267 -       case NFPROTO_IPV4:
268 -               if (unlikely(skb->len < sizeof(struct iphdr) ||
269 -                            ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
270 -                       if (net_ratelimit())
271 -                               pr_info("ignoring short SOCK_RAW packet\n");
272 -                       return NF_ACCEPT;
273 -               }
274 -               nft_set_pktinfo_ipv4(&pkt, skb);
275 -               break;
276 -       case NFPROTO_IPV6:
277 -               if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
278 -                       if (net_ratelimit())
279 -                               pr_info("ignoring short SOCK_RAW packet\n");
280 -                       return NF_ACCEPT;
281 -               }
282 -               nft_set_pktinfo_ipv6(&pkt, skb);
283 -               break;
284 -       default:
285 -               break;
286 -       }
287 -
288 -       return nft_do_chain(&pkt, priv);
289 -}
290 -
291  static struct nft_af_info nft_af_inet __read_mostly = {
292         .family         = NFPROTO_INET,
293         .nhooks         = NF_INET_NUMHOOKS,
294 @@ -116,7 +84,7 @@ static const struct nf_chain_type filter
295                           (1 << NF_INET_POST_ROUTING),
296         .hooks          = {
297                 [NF_INET_LOCAL_IN]      = nft_do_chain_inet,
298 -               [NF_INET_LOCAL_OUT]     = nft_inet_output,
299 +               [NF_INET_LOCAL_OUT]     = nft_do_chain_inet,
300                 [NF_INET_FORWARD]       = nft_do_chain_inet,
301                 [NF_INET_PRE_ROUTING]   = nft_do_chain_inet,
302                 [NF_INET_POST_ROUTING]  = nft_do_chain_inet,