Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IPSEC]: Move state lock into x->type->input

This patch releases the lock on the state before calling
x->type->input. It also adds the lock to the spots where they're
currently needed.

Most of those places (all except mip6) are expected to disappear with
async crypto.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
0ebea8ef 668dc8af

+77 -41
+10 -4
net/ipv4/ah4.c
··· 169 169 if (ip_clear_mutable_options(iph, &dummy)) 170 170 goto out; 171 171 } 172 + 173 + spin_lock(&x->lock); 172 174 { 173 175 u8 auth_data[MAX_AH_AUTH_LEN]; 174 176 ··· 178 176 skb_push(skb, ihl); 179 177 err = ah_mac_digest(ahp, skb, ah->auth_data); 180 178 if (err) 181 - goto out; 182 - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { 179 + goto unlock; 180 + if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) 183 181 err = -EBADMSG; 184 - goto out; 185 - } 186 182 } 183 + unlock: 184 + spin_unlock(&x->lock); 185 + 186 + if (err) 187 + goto out; 188 + 187 189 skb->network_header += ah_hlen; 188 190 memcpy(skb_network_header(skb), work_buf, ihl); 189 191 skb->transport_header = skb->network_header;
+15 -9
net/ipv4/esp4.c
··· 171 171 if (elen <= 0 || (elen & (blksize-1))) 172 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 182 /* If integrity check is required, do this. */ 175 183 if (esp->auth.icv_full_len) { 176 184 u8 sum[alen]; 177 185 178 186 err = esp_mac_digest(esp, skb, 0, skb->len - alen); 179 187 if (err) 180 - goto out; 188 + goto unlock; 181 189 182 190 if (skb_copy_bits(skb, skb->len - alen, sum, alen)) 183 191 BUG(); 184 192 185 193 if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { 186 194 err = -EBADMSG; 187 - goto out; 195 + goto unlock; 188 196 } 189 197 } 190 - 191 - if ((err = skb_cow_data(skb, 0, &trailer)) < 0) 192 - goto out; 193 - nfrags = err; 194 - 195 - skb->ip_summed = CHECKSUM_NONE; 196 198 197 199 esph = (struct ip_esp_hdr *)skb->data; 198 200 ··· 208 206 err = -ENOMEM; 209 207 sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); 210 208 if (!sg) 211 - goto out; 209 + goto unlock; 212 210 } 213 211 sg_init_table(sg, nfrags); 214 212 skb_to_sgvec(skb, sg, ··· 217 215 err = crypto_blkcipher_decrypt(&desc, sg, sg, elen); 218 216 if (unlikely(sg != &esp->sgbuf[0])) 219 217 kfree(sg); 218 + 219 + unlock: 220 + spin_unlock(&x->lock); 221 + 220 222 if (unlikely(err)) 221 223 goto out; 222 224
+7 -2
net/ipv6/ah6.c
··· 370 370 ip6h->flow_lbl[2] = 0; 371 371 ip6h->hop_limit = 0; 372 372 373 + spin_lock(&x->lock); 373 374 { 374 375 u8 auth_data[MAX_AH_AUTH_LEN]; 375 376 ··· 379 378 skb_push(skb, hdr_len); 380 379 err = ah_mac_digest(ahp, skb, ah->auth_data); 381 380 if (err) 382 - goto free_out; 381 + goto unlock; 383 382 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { 384 383 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); 385 384 err = -EBADMSG; 386 - goto free_out; 387 385 } 388 386 } 387 + unlock: 388 + spin_unlock(&x->lock); 389 + 390 + if (err) 391 + goto free_out; 389 392 390 393 skb->network_header += ah_hlen; 391 394 memcpy(skb_network_header(skb), tmp_hdr, hdr_len);
+31 -22
net/ipv6/esp6.c
··· 165 165 goto out; 166 166 } 167 167 168 - /* If integrity check is required, do this. */ 169 - if (esp->auth.icv_full_len) { 170 - u8 sum[alen]; 171 - 172 - ret = esp_mac_digest(esp, skb, 0, skb->len - alen); 173 - if (ret) 174 - goto out; 175 - 176 - if (skb_copy_bits(skb, skb->len - alen, sum, alen)) 177 - BUG(); 178 - 179 - if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { 180 - ret = -EBADMSG; 181 - goto out; 182 - } 183 - } 184 - 185 168 if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) { 186 169 ret = -EINVAL; 187 170 goto out; 188 171 } 189 172 190 173 skb->ip_summed = CHECKSUM_NONE; 174 + 175 + spin_lock(&x->lock); 176 + 177 + /* If integrity check is required, do this. */ 178 + if (esp->auth.icv_full_len) { 179 + u8 sum[alen]; 180 + 181 + ret = esp_mac_digest(esp, skb, 0, skb->len - alen); 182 + if (ret) 183 + goto unlock; 184 + 185 + if (skb_copy_bits(skb, skb->len - alen, sum, alen)) 186 + BUG(); 187 + 188 + if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { 189 + ret = -EBADMSG; 190 + goto unlock; 191 + } 192 + } 191 193 192 194 esph = (struct ip_esp_hdr *)skb->data; 193 195 iph = ipv6_hdr(skb); ··· 199 197 crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen); 200 198 201 199 { 202 - u8 nexthdr[2]; 203 200 struct scatterlist *sg = &esp->sgbuf[0]; 204 - u8 padlen; 205 201 206 202 if (unlikely(nfrags > ESP_NUM_FAST_SG)) { 207 203 sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); 208 204 if (!sg) { 209 205 ret = -ENOMEM; 210 - goto out; 206 + goto unlock; 211 207 } 212 208 } 213 209 sg_init_table(sg, nfrags); ··· 215 215 ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen); 216 216 if (unlikely(sg != &esp->sgbuf[0])) 217 217 kfree(sg); 218 - if (unlikely(ret)) 219 - goto out; 218 + } 219 + 220 + unlock: 221 + spin_unlock(&x->lock); 222 + 223 + if (unlikely(ret)) 224 + goto out; 225 + 226 + { 227 + u8 nexthdr[2]; 228 + u8 padlen; 220 229 221 230 if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) 222 231 BUG();
+10 -4
net/ipv6/mip6.c
··· 128 128 { 129 129 struct ipv6hdr *iph = ipv6_hdr(skb); 130 130 struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; 131 + int err = destopt->nexthdr; 131 132 133 + spin_lock(&x->lock); 132 134 if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) && 133 135 !ipv6_addr_any((struct in6_addr *)x->coaddr)) 134 - return -ENOENT; 136 + err = -ENOENT; 137 + spin_unlock(&x->lock); 135 138 136 - return destopt->nexthdr; 139 + return err; 137 140 } 138 141 139 142 /* Destination Option Header is inserted. ··· 347 344 static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) 348 345 { 349 346 struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; 347 + int err = rt2->rt_hdr.nexthdr; 350 348 349 + spin_lock(&x->lock); 351 350 if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) && 352 351 !ipv6_addr_any((struct in6_addr *)x->coaddr)) 353 - return -ENOENT; 352 + err = -ENOENT; 353 + spin_unlock(&x->lock); 354 354 355 - return rt2->rt_hdr.nexthdr; 355 + return err; 356 356 } 357 357 358 358 /* Routing Header type 2 is inserted.
+4
net/xfrm/xfrm_input.c
··· 146 146 if (xfrm_state_check_expire(x)) 147 147 goto drop_unlock; 148 148 149 + spin_unlock(&x->lock); 150 + 149 151 nexthdr = x->type->input(x, skb); 152 + 153 + spin_lock(&x->lock); 150 154 if (nexthdr <= 0) { 151 155 if (nexthdr == -EBADMSG) 152 156 x->stats.integrity_failed++;