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 | |
| 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>
| -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: |
