diff options
Diffstat (limited to 'net/ipv4/esp4.c')
-rw-r--r-- | net/ipv4/esp4.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 3350a7d50669..28ea5c77ca23 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -171,29 +171,31 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
171 | if (elen <= 0 || (elen & (blksize-1))) | 171 | if (elen <= 0 || (elen & (blksize-1))) |
172 | goto out; | 172 | goto out; |
173 | 173 | ||
174 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) | ||
175 | goto out; | ||
176 | nfrags = err; | ||
177 | |||
178 | skb->ip_summed = CHECKSUM_NONE; | ||
179 | |||
180 | spin_lock(&x->lock); | ||
181 | |||
174 | /* If integrity check is required, do this. */ | 182 | /* If integrity check is required, do this. */ |
175 | if (esp->auth.icv_full_len) { | 183 | if (esp->auth.icv_full_len) { |
176 | u8 sum[alen]; | 184 | u8 sum[alen]; |
177 | 185 | ||
178 | err = esp_mac_digest(esp, skb, 0, skb->len - alen); | 186 | err = esp_mac_digest(esp, skb, 0, skb->len - alen); |
179 | if (err) | 187 | if (err) |
180 | goto out; | 188 | goto unlock; |
181 | 189 | ||
182 | if (skb_copy_bits(skb, skb->len - alen, sum, alen)) | 190 | if (skb_copy_bits(skb, skb->len - alen, sum, alen)) |
183 | BUG(); | 191 | BUG(); |
184 | 192 | ||
185 | if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { | 193 | if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { |
186 | err = -EBADMSG; | 194 | err = -EBADMSG; |
187 | goto out; | 195 | goto unlock; |
188 | } | 196 | } |
189 | } | 197 | } |
190 | 198 | ||
191 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) | ||
192 | goto out; | ||
193 | nfrags = err; | ||
194 | |||
195 | skb->ip_summed = CHECKSUM_NONE; | ||
196 | |||
197 | esph = (struct ip_esp_hdr *)skb->data; | 199 | esph = (struct ip_esp_hdr *)skb->data; |
198 | 200 | ||
199 | /* Get ivec. This can be wrong, check against another impls. */ | 201 | /* Get ivec. This can be wrong, check against another impls. */ |
@@ -206,7 +208,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
206 | err = -ENOMEM; | 208 | err = -ENOMEM; |
207 | sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); | 209 | sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); |
208 | if (!sg) | 210 | if (!sg) |
209 | goto out; | 211 | goto unlock; |
210 | } | 212 | } |
211 | sg_init_table(sg, nfrags); | 213 | sg_init_table(sg, nfrags); |
212 | skb_to_sgvec(skb, sg, | 214 | skb_to_sgvec(skb, sg, |
@@ -215,6 +217,10 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
215 | err = crypto_blkcipher_decrypt(&desc, sg, sg, elen); | 217 | err = crypto_blkcipher_decrypt(&desc, sg, sg, elen); |
216 | if (unlikely(sg != &esp->sgbuf[0])) | 218 | if (unlikely(sg != &esp->sgbuf[0])) |
217 | kfree(sg); | 219 | kfree(sg); |
220 | |||
221 | unlock: | ||
222 | spin_unlock(&x->lock); | ||
223 | |||
218 | if (unlikely(err)) | 224 | if (unlikely(err)) |
219 | goto out; | 225 | goto out; |
220 | 226 | ||