diff options
author | Changli Gao <xiaosuo@gmail.com> | 2010-08-04 00:48:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-08-05 00:53:15 -0400 |
commit | 4b95c3d40d7d9927438ed7b7b49c84c60e27b65b (patch) | |
tree | 322f6e8e9f044accae4eda032b04d1daeec00358 /net/sched | |
parent | f9599ce11192f24dbb0f4fdb70121a05edc58342 (diff) |
cls_flow: add sanity check for the packet length
The packet length should be checked before the packet data is dereferenced.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/cls_flow.c | 96 |
1 files changed, 56 insertions, 40 deletions
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index f73542d2cdd0..e17096e3913c 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
@@ -65,37 +65,47 @@ static inline u32 addr_fold(void *addr) | |||
65 | return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); | 65 | return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); |
66 | } | 66 | } |
67 | 67 | ||
68 | static u32 flow_get_src(const struct sk_buff *skb) | 68 | static u32 flow_get_src(struct sk_buff *skb) |
69 | { | 69 | { |
70 | switch (skb->protocol) { | 70 | switch (skb->protocol) { |
71 | case htons(ETH_P_IP): | 71 | case htons(ETH_P_IP): |
72 | return ntohl(ip_hdr(skb)->saddr); | 72 | if (pskb_network_may_pull(skb, sizeof(struct iphdr))) |
73 | return ntohl(ip_hdr(skb)->saddr); | ||
74 | break; | ||
73 | case htons(ETH_P_IPV6): | 75 | case htons(ETH_P_IPV6): |
74 | return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); | 76 | if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) |
75 | default: | 77 | return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); |
76 | return addr_fold(skb->sk); | 78 | break; |
77 | } | 79 | } |
80 | |||
81 | return addr_fold(skb->sk); | ||
78 | } | 82 | } |
79 | 83 | ||
80 | static u32 flow_get_dst(const struct sk_buff *skb) | 84 | static u32 flow_get_dst(struct sk_buff *skb) |
81 | { | 85 | { |
82 | switch (skb->protocol) { | 86 | switch (skb->protocol) { |
83 | case htons(ETH_P_IP): | 87 | case htons(ETH_P_IP): |
84 | return ntohl(ip_hdr(skb)->daddr); | 88 | if (pskb_network_may_pull(skb, sizeof(struct iphdr))) |
89 | return ntohl(ip_hdr(skb)->daddr); | ||
90 | break; | ||
85 | case htons(ETH_P_IPV6): | 91 | case htons(ETH_P_IPV6): |
86 | return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); | 92 | if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) |
87 | default: | 93 | return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); |
88 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | 94 | break; |
89 | } | 95 | } |
96 | |||
97 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | ||
90 | } | 98 | } |
91 | 99 | ||
92 | static u32 flow_get_proto(const struct sk_buff *skb) | 100 | static u32 flow_get_proto(struct sk_buff *skb) |
93 | { | 101 | { |
94 | switch (skb->protocol) { | 102 | switch (skb->protocol) { |
95 | case htons(ETH_P_IP): | 103 | case htons(ETH_P_IP): |
96 | return ip_hdr(skb)->protocol; | 104 | return pskb_network_may_pull(skb, sizeof(struct iphdr)) ? |
105 | ip_hdr(skb)->protocol : 0; | ||
97 | case htons(ETH_P_IPV6): | 106 | case htons(ETH_P_IPV6): |
98 | return ipv6_hdr(skb)->nexthdr; | 107 | return pskb_network_may_pull(skb, sizeof(struct ipv6hdr)) ? |
108 | ipv6_hdr(skb)->nexthdr : 0; | ||
99 | default: | 109 | default: |
100 | return 0; | 110 | return 0; |
101 | } | 111 | } |
@@ -116,58 +126,64 @@ static int has_ports(u8 protocol) | |||
116 | } | 126 | } |
117 | } | 127 | } |
118 | 128 | ||
119 | static u32 flow_get_proto_src(const struct sk_buff *skb) | 129 | static u32 flow_get_proto_src(struct sk_buff *skb) |
120 | { | 130 | { |
121 | u32 res = 0; | ||
122 | |||
123 | switch (skb->protocol) { | 131 | switch (skb->protocol) { |
124 | case htons(ETH_P_IP): { | 132 | case htons(ETH_P_IP): { |
125 | struct iphdr *iph = ip_hdr(skb); | 133 | struct iphdr *iph; |
126 | 134 | ||
135 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | ||
136 | break; | ||
137 | iph = ip_hdr(skb); | ||
127 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 138 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && |
128 | has_ports(iph->protocol)) | 139 | has_ports(iph->protocol) && |
129 | res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); | 140 | pskb_network_may_pull(skb, iph->ihl * 4 + 2)) |
141 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); | ||
130 | break; | 142 | break; |
131 | } | 143 | } |
132 | case htons(ETH_P_IPV6): { | 144 | case htons(ETH_P_IPV6): { |
133 | struct ipv6hdr *iph = ipv6_hdr(skb); | 145 | struct ipv6hdr *iph; |
134 | 146 | ||
147 | if (!pskb_network_may_pull(skb, sizeof(*iph) + 2)) | ||
148 | break; | ||
149 | iph = ipv6_hdr(skb); | ||
135 | if (has_ports(iph->nexthdr)) | 150 | if (has_ports(iph->nexthdr)) |
136 | res = ntohs(*(__be16 *)&iph[1]); | 151 | return ntohs(*(__be16 *)&iph[1]); |
137 | break; | 152 | break; |
138 | } | 153 | } |
139 | default: | ||
140 | res = addr_fold(skb->sk); | ||
141 | } | 154 | } |
142 | 155 | ||
143 | return res; | 156 | return addr_fold(skb->sk); |
144 | } | 157 | } |
145 | 158 | ||
146 | static u32 flow_get_proto_dst(const struct sk_buff *skb) | 159 | static u32 flow_get_proto_dst(struct sk_buff *skb) |
147 | { | 160 | { |
148 | u32 res = 0; | ||
149 | |||
150 | switch (skb->protocol) { | 161 | switch (skb->protocol) { |
151 | case htons(ETH_P_IP): { | 162 | case htons(ETH_P_IP): { |
152 | struct iphdr *iph = ip_hdr(skb); | 163 | struct iphdr *iph; |
153 | 164 | ||
165 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | ||
166 | break; | ||
167 | iph = ip_hdr(skb); | ||
154 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 168 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && |
155 | has_ports(iph->protocol)) | 169 | has_ports(iph->protocol) && |
156 | res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); | 170 | pskb_network_may_pull(skb, iph->ihl * 4 + 4)) |
171 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); | ||
157 | break; | 172 | break; |
158 | } | 173 | } |
159 | case htons(ETH_P_IPV6): { | 174 | case htons(ETH_P_IPV6): { |
160 | struct ipv6hdr *iph = ipv6_hdr(skb); | 175 | struct ipv6hdr *iph; |
161 | 176 | ||
177 | if (!pskb_network_may_pull(skb, sizeof(*iph) + 4)) | ||
178 | break; | ||
179 | iph = ipv6_hdr(skb); | ||
162 | if (has_ports(iph->nexthdr)) | 180 | if (has_ports(iph->nexthdr)) |
163 | res = ntohs(*(__be16 *)((void *)&iph[1] + 2)); | 181 | return ntohs(*(__be16 *)((void *)&iph[1] + 2)); |
164 | break; | 182 | break; |
165 | } | 183 | } |
166 | default: | ||
167 | res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | ||
168 | } | 184 | } |
169 | 185 | ||
170 | return res; | 186 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; |
171 | } | 187 | } |
172 | 188 | ||
173 | static u32 flow_get_iif(const struct sk_buff *skb) | 189 | static u32 flow_get_iif(const struct sk_buff *skb) |
@@ -211,7 +227,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb) | |||
211 | }) | 227 | }) |
212 | #endif | 228 | #endif |
213 | 229 | ||
214 | static u32 flow_get_nfct_src(const struct sk_buff *skb) | 230 | static u32 flow_get_nfct_src(struct sk_buff *skb) |
215 | { | 231 | { |
216 | switch (skb->protocol) { | 232 | switch (skb->protocol) { |
217 | case htons(ETH_P_IP): | 233 | case htons(ETH_P_IP): |
@@ -223,7 +239,7 @@ fallback: | |||
223 | return flow_get_src(skb); | 239 | return flow_get_src(skb); |
224 | } | 240 | } |
225 | 241 | ||
226 | static u32 flow_get_nfct_dst(const struct sk_buff *skb) | 242 | static u32 flow_get_nfct_dst(struct sk_buff *skb) |
227 | { | 243 | { |
228 | switch (skb->protocol) { | 244 | switch (skb->protocol) { |
229 | case htons(ETH_P_IP): | 245 | case htons(ETH_P_IP): |
@@ -235,14 +251,14 @@ fallback: | |||
235 | return flow_get_dst(skb); | 251 | return flow_get_dst(skb); |
236 | } | 252 | } |
237 | 253 | ||
238 | static u32 flow_get_nfct_proto_src(const struct sk_buff *skb) | 254 | static u32 flow_get_nfct_proto_src(struct sk_buff *skb) |
239 | { | 255 | { |
240 | return ntohs(CTTUPLE(skb, src.u.all)); | 256 | return ntohs(CTTUPLE(skb, src.u.all)); |
241 | fallback: | 257 | fallback: |
242 | return flow_get_proto_src(skb); | 258 | return flow_get_proto_src(skb); |
243 | } | 259 | } |
244 | 260 | ||
245 | static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb) | 261 | static u32 flow_get_nfct_proto_dst(struct sk_buff *skb) |
246 | { | 262 | { |
247 | return ntohs(CTTUPLE(skb, dst.u.all)); | 263 | return ntohs(CTTUPLE(skb, dst.u.all)); |
248 | fallback: | 264 | fallback: |
@@ -281,7 +297,7 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb) | |||
281 | return tag & VLAN_VID_MASK; | 297 | return tag & VLAN_VID_MASK; |
282 | } | 298 | } |
283 | 299 | ||
284 | static u32 flow_key_get(const struct sk_buff *skb, int key) | 300 | static u32 flow_key_get(struct sk_buff *skb, int key) |
285 | { | 301 | { |
286 | switch (key) { | 302 | switch (key) { |
287 | case FLOW_KEY_SRC: | 303 | case FLOW_KEY_SRC: |