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

nitro_enclaves: Add logic for terminating an enclave

An enclave is associated with an fd that is returned after the enclave
creation logic is completed. This enclave fd is further used to setup
enclave resources. Once the enclave needs to be terminated, the enclave
fd is closed.

Add logic for enclave termination, that is mapped to the enclave fd
release callback. Free the internal enclave info used for bookkeeping.

Changelog

v9 -> v10

* Update commit message to include the changelog before the SoB tag(s).

v8 -> v9

* Use the ne_devs data structure to get the refs for the NE PCI device.

v7 -> v8

* No changes.

v6 -> v7

* Remove the pci_dev_put() call as the NE misc device parent field is
used now to get the NE PCI device.
* Update the naming and add more comments to make more clear the logic
of handling full CPU cores and dedicating them to the enclave.

v5 -> v6

* Update documentation to kernel-doc format.
* Use directly put_page() instead of unpin_user_pages(), to match the
get_user_pages() calls.

v4 -> v5

* Release the reference to the NE PCI device on enclave fd release.
* Adapt the logic to cpumask enclave vCPU ids and CPU cores.
* Remove sanity checks for situations that shouldn't happen, only if
buggy system or broken logic at all.

v3 -> v4

* Use dev_err instead of custom NE log pattern.

v2 -> v3

* Remove the WARN_ON calls.
* Update static calls sanity checks.
* Update kzfree() calls to kfree().

v1 -> v2

* Add log pattern for NE.
* Remove the BUG_ON calls.
* Update goto labels to match their purpose.
* Add early exit in release() if there was a slot alloc error in the fd
creation path.

Reviewed-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Alexandru Vasile <lexnv@amazon.com>
Signed-off-by: Andra Paraschiv <andraprs@amazon.com>
Link: https://lore.kernel.org/r/20200921121732.44291-14-andraprs@amazon.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andra Paraschiv and committed by
Greg Kroah-Hartman
9c8eb50f 111c775a

+166
+166
drivers/virt/nitro_enclaves/ne_misc_dev.c
··· 1325 1325 } 1326 1326 1327 1327 /** 1328 + * ne_enclave_remove_all_mem_region_entries() - Remove all memory region entries 1329 + * from the enclave data structure. 1330 + * @ne_enclave : Private data associated with the current enclave. 1331 + * 1332 + * Context: Process context. This function is called with the ne_enclave mutex held. 1333 + */ 1334 + static void ne_enclave_remove_all_mem_region_entries(struct ne_enclave *ne_enclave) 1335 + { 1336 + unsigned long i = 0; 1337 + struct ne_mem_region *ne_mem_region = NULL; 1338 + struct ne_mem_region *ne_mem_region_tmp = NULL; 1339 + 1340 + list_for_each_entry_safe(ne_mem_region, ne_mem_region_tmp, 1341 + &ne_enclave->mem_regions_list, 1342 + mem_region_list_entry) { 1343 + list_del(&ne_mem_region->mem_region_list_entry); 1344 + 1345 + for (i = 0; i < ne_mem_region->nr_pages; i++) 1346 + put_page(ne_mem_region->pages[i]); 1347 + 1348 + kfree(ne_mem_region->pages); 1349 + 1350 + kfree(ne_mem_region); 1351 + } 1352 + } 1353 + 1354 + /** 1355 + * ne_enclave_remove_all_vcpu_id_entries() - Remove all vCPU id entries from 1356 + * the enclave data structure. 1357 + * @ne_enclave : Private data associated with the current enclave. 1358 + * 1359 + * Context: Process context. This function is called with the ne_enclave mutex held. 1360 + */ 1361 + static void ne_enclave_remove_all_vcpu_id_entries(struct ne_enclave *ne_enclave) 1362 + { 1363 + unsigned int cpu = 0; 1364 + unsigned int i = 0; 1365 + 1366 + mutex_lock(&ne_cpu_pool.mutex); 1367 + 1368 + for (i = 0; i < ne_enclave->nr_parent_vm_cores; i++) { 1369 + for_each_cpu(cpu, ne_enclave->threads_per_core[i]) 1370 + /* Update the available NE CPU pool. */ 1371 + cpumask_set_cpu(cpu, ne_cpu_pool.avail_threads_per_core[i]); 1372 + 1373 + free_cpumask_var(ne_enclave->threads_per_core[i]); 1374 + } 1375 + 1376 + mutex_unlock(&ne_cpu_pool.mutex); 1377 + 1378 + kfree(ne_enclave->threads_per_core); 1379 + 1380 + free_cpumask_var(ne_enclave->vcpu_ids); 1381 + } 1382 + 1383 + /** 1384 + * ne_pci_dev_remove_enclave_entry() - Remove the enclave entry from the data 1385 + * structure that is part of the NE PCI 1386 + * device private data. 1387 + * @ne_enclave : Private data associated with the current enclave. 1388 + * @ne_pci_dev : Private data associated with the PCI device. 1389 + * 1390 + * Context: Process context. This function is called with the ne_pci_dev enclave 1391 + * mutex held. 1392 + */ 1393 + static void ne_pci_dev_remove_enclave_entry(struct ne_enclave *ne_enclave, 1394 + struct ne_pci_dev *ne_pci_dev) 1395 + { 1396 + struct ne_enclave *ne_enclave_entry = NULL; 1397 + struct ne_enclave *ne_enclave_entry_tmp = NULL; 1398 + 1399 + list_for_each_entry_safe(ne_enclave_entry, ne_enclave_entry_tmp, 1400 + &ne_pci_dev->enclaves_list, enclave_list_entry) { 1401 + if (ne_enclave_entry->slot_uid == ne_enclave->slot_uid) { 1402 + list_del(&ne_enclave_entry->enclave_list_entry); 1403 + 1404 + break; 1405 + } 1406 + } 1407 + } 1408 + 1409 + /** 1410 + * ne_enclave_release() - Release function provided by the enclave file. 1411 + * @inode: Inode associated with this file release function. 1412 + * @file: File associated with this release function. 1413 + * 1414 + * Context: Process context. 1415 + * Return: 1416 + * * 0 on success. 1417 + * * Negative return value on failure. 1418 + */ 1419 + static int ne_enclave_release(struct inode *inode, struct file *file) 1420 + { 1421 + struct ne_pci_dev_cmd_reply cmd_reply = {}; 1422 + struct enclave_stop_req enclave_stop_request = {}; 1423 + struct ne_enclave *ne_enclave = file->private_data; 1424 + struct ne_pci_dev *ne_pci_dev = ne_devs.ne_pci_dev; 1425 + struct pci_dev *pdev = ne_pci_dev->pdev; 1426 + int rc = -EINVAL; 1427 + struct slot_free_req slot_free_req = {}; 1428 + 1429 + if (!ne_enclave) 1430 + return 0; 1431 + 1432 + /* 1433 + * Early exit in case there is an error in the enclave creation logic 1434 + * and fput() is called on the cleanup path. 1435 + */ 1436 + if (!ne_enclave->slot_uid) 1437 + return 0; 1438 + 1439 + /* 1440 + * Acquire the enclave list mutex before the enclave mutex 1441 + * in order to avoid deadlocks with @ref ne_event_work_handler. 1442 + */ 1443 + mutex_lock(&ne_pci_dev->enclaves_list_mutex); 1444 + mutex_lock(&ne_enclave->enclave_info_mutex); 1445 + 1446 + if (ne_enclave->state != NE_STATE_INIT && ne_enclave->state != NE_STATE_STOPPED) { 1447 + enclave_stop_request.slot_uid = ne_enclave->slot_uid; 1448 + 1449 + rc = ne_do_request(pdev, ENCLAVE_STOP, 1450 + &enclave_stop_request, sizeof(enclave_stop_request), 1451 + &cmd_reply, sizeof(cmd_reply)); 1452 + if (rc < 0) { 1453 + dev_err_ratelimited(ne_misc_dev.this_device, 1454 + "Error in enclave stop [rc=%d]\n", rc); 1455 + 1456 + goto unlock_mutex; 1457 + } 1458 + 1459 + memset(&cmd_reply, 0, sizeof(cmd_reply)); 1460 + } 1461 + 1462 + slot_free_req.slot_uid = ne_enclave->slot_uid; 1463 + 1464 + rc = ne_do_request(pdev, SLOT_FREE, 1465 + &slot_free_req, sizeof(slot_free_req), 1466 + &cmd_reply, sizeof(cmd_reply)); 1467 + if (rc < 0) { 1468 + dev_err_ratelimited(ne_misc_dev.this_device, 1469 + "Error in slot free [rc=%d]\n", rc); 1470 + 1471 + goto unlock_mutex; 1472 + } 1473 + 1474 + ne_pci_dev_remove_enclave_entry(ne_enclave, ne_pci_dev); 1475 + ne_enclave_remove_all_mem_region_entries(ne_enclave); 1476 + ne_enclave_remove_all_vcpu_id_entries(ne_enclave); 1477 + 1478 + mutex_unlock(&ne_enclave->enclave_info_mutex); 1479 + mutex_unlock(&ne_pci_dev->enclaves_list_mutex); 1480 + 1481 + kfree(ne_enclave); 1482 + 1483 + return 0; 1484 + 1485 + unlock_mutex: 1486 + mutex_unlock(&ne_enclave->enclave_info_mutex); 1487 + mutex_unlock(&ne_pci_dev->enclaves_list_mutex); 1488 + 1489 + return rc; 1490 + } 1491 + 1492 + /** 1328 1493 * ne_enclave_poll() - Poll functionality used for enclave out-of-band events. 1329 1494 * @file: File associated with this poll function. 1330 1495 * @wait: Poll table data structure. ··· 1518 1353 .llseek = noop_llseek, 1519 1354 .poll = ne_enclave_poll, 1520 1355 .unlocked_ioctl = ne_enclave_ioctl, 1356 + .release = ne_enclave_release, 1521 1357 }; 1522 1358 1523 1359 /**