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

Merge branch 'xfrm: fixes for xfrm_state_find under preemption'

Sabrina Dubroca says:

====================
While looking at the pcpu_id changes, I found two issues that can
happen if we get preempted and the cpu_id changes. The second patch
takes care of both problems. The first patch also makes sure we don't
use state_ptrs uninitialized, which could currently happen. syzbot
seems to have hit this issue [1].

[1] https://syzkaller.appspot.com/bug?extid=7ed9d47e15e88581dc5b
====================

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

+8 -15
+8 -15
net/xfrm/xfrm_state.c
··· 1307 1307 static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, 1308 1308 const struct flowi *fl, unsigned short family, 1309 1309 struct xfrm_state **best, int *acq_in_progress, 1310 - int *error) 1310 + int *error, unsigned int pcpu_id) 1311 1311 { 1312 - /* We need the cpu id just as a lookup key, 1313 - * we don't require it to be stable. 1314 - */ 1315 - unsigned int pcpu_id = get_cpu(); 1316 - put_cpu(); 1317 - 1318 1312 /* Resolution logic: 1319 1313 * 1. There is a valid state with matching selector. Done. 1320 1314 * 2. Valid state with inappropriate selector. Skip. ··· 1375 1381 /* We need the cpu id just as a lookup key, 1376 1382 * we don't require it to be stable. 1377 1383 */ 1378 - pcpu_id = get_cpu(); 1379 - put_cpu(); 1384 + pcpu_id = raw_smp_processor_id(); 1380 1385 1381 1386 to_put = NULL; 1382 1387 1383 1388 sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation); 1384 1389 1385 1390 rcu_read_lock(); 1391 + xfrm_hash_ptrs_get(net, &state_ptrs); 1392 + 1386 1393 hlist_for_each_entry_rcu(x, &pol->state_cache_list, state_cache) { 1387 1394 if (x->props.family == encap_family && 1388 1395 x->props.reqid == tmpl->reqid && ··· 1395 1400 tmpl->id.proto == x->id.proto && 1396 1401 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1397 1402 xfrm_state_look_at(pol, x, fl, encap_family, 1398 - &best, &acquire_in_progress, &error); 1403 + &best, &acquire_in_progress, &error, pcpu_id); 1399 1404 } 1400 1405 1401 1406 if (best) ··· 1412 1417 tmpl->id.proto == x->id.proto && 1413 1418 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1414 1419 xfrm_state_look_at(pol, x, fl, family, 1415 - &best, &acquire_in_progress, &error); 1420 + &best, &acquire_in_progress, &error, pcpu_id); 1416 1421 } 1417 1422 1418 1423 cached: ··· 1423 1428 best = NULL; 1424 1429 else if (acquire_in_progress) /* XXX: acquire_in_progress should not happen */ 1425 1430 WARN_ON(1); 1426 - 1427 - xfrm_hash_ptrs_get(net, &state_ptrs); 1428 1431 1429 1432 h = __xfrm_dst_hash(daddr, saddr, tmpl->reqid, encap_family, state_ptrs.hmask); 1430 1433 hlist_for_each_entry_rcu(x, state_ptrs.bydst + h, bydst) { ··· 1453 1460 tmpl->id.proto == x->id.proto && 1454 1461 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1455 1462 xfrm_state_look_at(pol, x, fl, family, 1456 - &best, &acquire_in_progress, &error); 1463 + &best, &acquire_in_progress, &error, pcpu_id); 1457 1464 } 1458 1465 if (best || acquire_in_progress) 1459 1466 goto found; ··· 1488 1495 tmpl->id.proto == x->id.proto && 1489 1496 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1490 1497 xfrm_state_look_at(pol, x, fl, family, 1491 - &best, &acquire_in_progress, &error); 1498 + &best, &acquire_in_progress, &error, pcpu_id); 1492 1499 } 1493 1500 1494 1501 found: