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

Merge tag 'thunderbolt-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into char-misc-next

Mika writes:

thunderbolt: Changes for v4.21 merge window

* tag 'thunderbolt-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
thunderbolt: Export IOMMU based DMA protection support to userspace
iommu/vt-d: Do not enable ATS for untrusted devices
iommu/vt-d: Force IOMMU on for platform opt in hint
PCI / ACPI: Identify untrusted PCI devices

+185 -3
+9
Documentation/ABI/testing/sysfs-bus-thunderbolt
··· 21 21 If a device is authorized automatically during boot its 22 22 boot attribute is set to 1. 23 23 24 + What: /sys/bus/thunderbolt/devices/.../domainX/iommu_dma_protection 25 + Date: Mar 2019 26 + KernelVersion: 4.21 27 + Contact: thunderbolt-software@lists.01.org 28 + Description: This attribute tells whether the system uses IOMMU 29 + for DMA protection. Value of 1 means IOMMU is used 0 means 30 + it is not (DMA protection is solely based on Thunderbolt 31 + security levels). 32 + 24 33 What: /sys/bus/thunderbolt/devices/.../domainX/security 25 34 Date: Sep 2017 26 35 KernelVersion: 4.13
+20
Documentation/admin-guide/thunderbolt.rst
··· 133 133 the device without a key or write a new key and write 1 to the 134 134 ``authorized`` file to get the new key stored on the device NVM. 135 135 136 + DMA protection utilizing IOMMU 137 + ------------------------------ 138 + Recent systems from 2018 and forward with Thunderbolt ports may natively 139 + support IOMMU. This means that Thunderbolt security is handled by an IOMMU 140 + so connected devices cannot access memory regions outside of what is 141 + allocated for them by drivers. When Linux is running on such system it 142 + automatically enables IOMMU if not enabled by the user already. These 143 + systems can be identified by reading ``1`` from 144 + ``/sys/bus/thunderbolt/devices/domainX/iommu_dma_protection`` attribute. 145 + 146 + The driver does not do anything special in this case but because DMA 147 + protection is handled by the IOMMU, security levels (if set) are 148 + redundant. For this reason some systems ship with security level set to 149 + ``none``. Other systems have security level set to ``user`` in order to 150 + support downgrade to older OS, so users who want to automatically 151 + authorize devices when IOMMU DMA protection is enabled can use the 152 + following ``udev`` rule:: 153 + 154 + ACTION=="add", SUBSYSTEM=="thunderbolt", ATTRS{iommu_dma_protection}=="1", ATTR{authorized}=="0", ATTR{authorized}="1" 155 + 136 156 Upgrading NVM on Thunderbolt device or host 137 157 ------------------------------------------- 138 158 Since most of the functionality is handled in firmware running on a
+11
drivers/acpi/property.c
··· 24 24 acpi_object_type type, 25 25 const union acpi_object **obj); 26 26 27 + /* 28 + * The GUIDs here are made equivalent to each other in order to avoid extra 29 + * complexity in the properties handling code, with the caveat that the 30 + * kernel will accept certain combinations of GUID and properties that are 31 + * not defined without a warning. For instance if any of the properties 32 + * from different GUID appear in a property list of another, it will be 33 + * accepted by the kernel. Firmware validation tools should catch these. 34 + */ 27 35 static const guid_t prp_guids[] = { 28 36 /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ 29 37 GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, ··· 39 31 /* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */ 40 32 GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3, 41 33 0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4), 34 + /* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */ 35 + GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3, 36 + 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89), 42 37 }; 43 38 44 39 static const guid_t ads_guid =
+25
drivers/iommu/dmar.c
··· 2042 2042 { 2043 2043 return dmar_device_hotplug(handle, false); 2044 2044 } 2045 + 2046 + /* 2047 + * dmar_platform_optin - Is %DMA_CTRL_PLATFORM_OPT_IN_FLAG set in DMAR table 2048 + * 2049 + * Returns true if the platform has %DMA_CTRL_PLATFORM_OPT_IN_FLAG set in 2050 + * the ACPI DMAR table. This means that the platform boot firmware has made 2051 + * sure no device can issue DMA outside of RMRR regions. 2052 + */ 2053 + bool dmar_platform_optin(void) 2054 + { 2055 + struct acpi_table_dmar *dmar; 2056 + acpi_status status; 2057 + bool ret; 2058 + 2059 + status = acpi_get_table(ACPI_SIG_DMAR, 0, 2060 + (struct acpi_table_header **)&dmar); 2061 + if (ACPI_FAILURE(status)) 2062 + return false; 2063 + 2064 + ret = !!(dmar->flags & DMAR_PLATFORM_OPT_IN); 2065 + acpi_put_table((struct acpi_table_header *)dmar); 2066 + 2067 + return ret; 2068 + } 2069 + EXPORT_SYMBOL_GPL(dmar_platform_optin);
+53 -3
drivers/iommu/intel-iommu.c
··· 184 184 */ 185 185 static int force_on = 0; 186 186 int intel_iommu_tboot_noforce; 187 + static int no_platform_optin; 187 188 188 189 #define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry)) 189 190 ··· 504 503 pr_info("IOMMU enabled\n"); 505 504 } else if (!strncmp(str, "off", 3)) { 506 505 dmar_disabled = 1; 506 + no_platform_optin = 1; 507 507 pr_info("IOMMU disabled\n"); 508 508 } else if (!strncmp(str, "igfx_off", 8)) { 509 509 dmar_map_gfx = 0; ··· 1473 1471 if (info->pri_supported && !pci_reset_pri(pdev) && !pci_enable_pri(pdev, 32)) 1474 1472 info->pri_enabled = 1; 1475 1473 #endif 1476 - if (info->ats_supported && !pci_enable_ats(pdev, VTD_PAGE_SHIFT)) { 1474 + if (!pdev->untrusted && info->ats_supported && 1475 + !pci_enable_ats(pdev, VTD_PAGE_SHIFT)) { 1477 1476 info->ats_enabled = 1; 1478 1477 domain_update_iotlb(info->domain); 1479 1478 info->ats_qdep = pci_ats_queue_depth(pdev); ··· 2896 2893 struct pci_dev *pdev = to_pci_dev(dev); 2897 2894 2898 2895 if (device_is_rmrr_locked(dev)) 2896 + return 0; 2897 + 2898 + /* 2899 + * Prevent any device marked as untrusted from getting 2900 + * placed into the statically identity mapping domain. 2901 + */ 2902 + if (pdev->untrusted) 2899 2903 return 0; 2900 2904 2901 2905 if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) ··· 4738 4728 NULL, 4739 4729 }; 4740 4730 4731 + static int __init platform_optin_force_iommu(void) 4732 + { 4733 + struct pci_dev *pdev = NULL; 4734 + bool has_untrusted_dev = false; 4735 + 4736 + if (!dmar_platform_optin() || no_platform_optin) 4737 + return 0; 4738 + 4739 + for_each_pci_dev(pdev) { 4740 + if (pdev->untrusted) { 4741 + has_untrusted_dev = true; 4742 + break; 4743 + } 4744 + } 4745 + 4746 + if (!has_untrusted_dev) 4747 + return 0; 4748 + 4749 + if (no_iommu || dmar_disabled) 4750 + pr_info("Intel-IOMMU force enabled due to platform opt in\n"); 4751 + 4752 + /* 4753 + * If Intel-IOMMU is disabled by default, we will apply identity 4754 + * map for all devices except those marked as being untrusted. 4755 + */ 4756 + if (dmar_disabled) 4757 + iommu_identity_mapping |= IDENTMAP_ALL; 4758 + 4759 + dmar_disabled = 0; 4760 + #if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB) 4761 + swiotlb = 0; 4762 + #endif 4763 + no_iommu = 0; 4764 + 4765 + return 1; 4766 + } 4767 + 4741 4768 int __init intel_iommu_init(void) 4742 4769 { 4743 4770 int ret = -ENODEV; 4744 4771 struct dmar_drhd_unit *drhd; 4745 4772 struct intel_iommu *iommu; 4746 4773 4747 - /* VT-d is required for a TXT/tboot launch, so enforce that */ 4748 - force_on = tboot_force_iommu(); 4774 + /* 4775 + * Intel IOMMU is required for a TXT/tboot launch or platform 4776 + * opt in, so enforce that. 4777 + */ 4778 + force_on = tboot_force_iommu() || platform_optin_force_iommu(); 4749 4779 4750 4780 if (iommu_init_mempool()) { 4751 4781 if (force_on)
+19
drivers/pci/pci-acpi.c
··· 789 789 ACPI_FREE(obj); 790 790 } 791 791 792 + static void pci_acpi_set_untrusted(struct pci_dev *dev) 793 + { 794 + u8 val; 795 + 796 + if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) 797 + return; 798 + if (device_property_read_u8(&dev->dev, "ExternalFacingPort", &val)) 799 + return; 800 + 801 + /* 802 + * These root ports expose PCIe (including DMA) outside of the 803 + * system so make sure we treat them and everything behind as 804 + * untrusted. 805 + */ 806 + if (val) 807 + dev->untrusted = 1; 808 + } 809 + 792 810 static void pci_acpi_setup(struct device *dev) 793 811 { 794 812 struct pci_dev *pci_dev = to_pci_dev(dev); ··· 816 798 return; 817 799 818 800 pci_acpi_optimize_delay(pci_dev, adev->handle); 801 + pci_acpi_set_untrusted(pci_dev); 819 802 820 803 pci_acpi_add_pm_notifier(adev, pci_dev); 821 804 if (!adev->wakeup.flags.valid)
+15
drivers/pci/probe.c
··· 1378 1378 } 1379 1379 } 1380 1380 1381 + static void set_pcie_untrusted(struct pci_dev *dev) 1382 + { 1383 + struct pci_dev *parent; 1384 + 1385 + /* 1386 + * If the upstream bridge is untrusted we treat this device 1387 + * untrusted as well. 1388 + */ 1389 + parent = pci_upstream_bridge(dev); 1390 + if (parent && parent->untrusted) 1391 + dev->untrusted = true; 1392 + } 1393 + 1381 1394 /** 1382 1395 * pci_ext_cfg_is_aliased - Is ext config space just an alias of std config? 1383 1396 * @dev: PCI device ··· 1650 1637 1651 1638 /* Need to have dev->cfg_size ready */ 1652 1639 set_pcie_thunderbolt(dev); 1640 + 1641 + set_pcie_untrusted(dev); 1653 1642 1654 1643 /* "Unknown power state" */ 1655 1644 dev->current_state = PCI_UNKNOWN;
+17
drivers/thunderbolt/domain.c
··· 7 7 */ 8 8 9 9 #include <linux/device.h> 10 + #include <linux/dmar.h> 10 11 #include <linux/idr.h> 12 + #include <linux/iommu.h> 11 13 #include <linux/module.h> 12 14 #include <linux/pm_runtime.h> 13 15 #include <linux/slab.h> ··· 238 236 } 239 237 static DEVICE_ATTR_RW(boot_acl); 240 238 239 + static ssize_t iommu_dma_protection_show(struct device *dev, 240 + struct device_attribute *attr, 241 + char *buf) 242 + { 243 + /* 244 + * Kernel DMA protection is a feature where Thunderbolt security is 245 + * handled natively using IOMMU. It is enabled when IOMMU is 246 + * enabled and ACPI DMAR table has DMAR_PLATFORM_OPT_IN set. 247 + */ 248 + return sprintf(buf, "%d\n", 249 + iommu_present(&pci_bus_type) && dmar_platform_optin()); 250 + } 251 + static DEVICE_ATTR_RO(iommu_dma_protection); 252 + 241 253 static ssize_t security_show(struct device *dev, struct device_attribute *attr, 242 254 char *buf) 243 255 { ··· 267 251 268 252 static struct attribute *domain_attrs[] = { 269 253 &dev_attr_boot_acl.attr, 254 + &dev_attr_iommu_dma_protection.attr, 270 255 &dev_attr_security.attr, 271 256 NULL, 272 257 };
+8
include/linux/dmar.h
··· 39 39 /* DMAR Flags */ 40 40 #define DMAR_INTR_REMAP 0x1 41 41 #define DMAR_X2APIC_OPT_OUT 0x2 42 + #define DMAR_PLATFORM_OPT_IN 0x4 42 43 43 44 struct intel_iommu; 44 45 ··· 171 170 { return 0; } 172 171 #endif /* CONFIG_IRQ_REMAP */ 173 172 173 + extern bool dmar_platform_optin(void); 174 + 174 175 #else /* CONFIG_DMAR_TABLE */ 175 176 176 177 static inline int dmar_device_add(void *handle) ··· 183 180 static inline int dmar_device_remove(void *handle) 184 181 { 185 182 return 0; 183 + } 184 + 185 + static inline bool dmar_platform_optin(void) 186 + { 187 + return false; 186 188 } 187 189 188 190 #endif /* CONFIG_DMAR_TABLE */
+8
include/linux/pci.h
··· 396 396 unsigned int is_hotplug_bridge:1; 397 397 unsigned int shpc_managed:1; /* SHPC owned by shpchp */ 398 398 unsigned int is_thunderbolt:1; /* Thunderbolt controller */ 399 + /* 400 + * Devices marked being untrusted are the ones that can potentially 401 + * execute DMA attacks and similar. They are typically connected 402 + * through external ports such as Thunderbolt but not limited to 403 + * that. When an IOMMU is enabled they should be getting full 404 + * mappings to make sure they cannot access arbitrary memory. 405 + */ 406 + unsigned int untrusted:1; 399 407 unsigned int __aer_firmware_first_valid:1; 400 408 unsigned int __aer_firmware_first:1; 401 409 unsigned int broken_intx_masking:1; /* INTx masking can't be used */