Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c20c809f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'thunderbolt-for-v4.21' of...

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
parents c4aa8b2a dcc3c9e3
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -21,6 +21,15 @@ Description: Holds a comma separated list of device unique_ids that
		If a device is authorized automatically during boot its
		boot attribute is set to 1.

What: /sys/bus/thunderbolt/devices/.../domainX/iommu_dma_protection
Date:		Mar 2019
KernelVersion:	4.21
Contact:	thunderbolt-software@lists.01.org
Description:	This attribute tells whether the system uses IOMMU
		for DMA protection. Value of 1 means IOMMU is used 0 means
		it is not (DMA protection is solely based on Thunderbolt
		security levels).

What: /sys/bus/thunderbolt/devices/.../domainX/security
Date:		Sep 2017
KernelVersion:	4.13
+20 −0
Original line number Diff line number Diff line
@@ -133,6 +133,26 @@ If the user still wants to connect the device they can either approve
the device without a key or write a new key and write 1 to the
``authorized`` file to get the new key stored on the device NVM.

DMA protection utilizing IOMMU
------------------------------
Recent systems from 2018 and forward with Thunderbolt ports may natively
support IOMMU. This means that Thunderbolt security is handled by an IOMMU
so connected devices cannot access memory regions outside of what is
allocated for them by drivers. When Linux is running on such system it
automatically enables IOMMU if not enabled by the user already. These
systems can be identified by reading ``1`` from
``/sys/bus/thunderbolt/devices/domainX/iommu_dma_protection`` attribute.

The driver does not do anything special in this case but because DMA
protection is handled by the IOMMU, security levels (if set) are
redundant. For this reason some systems ship with security level set to
``none``. Other systems have security level set to ``user`` in order to
support downgrade to older OS, so users who want to automatically
authorize devices when IOMMU DMA protection is enabled can use the
following ``udev`` rule::

  ACTION=="add", SUBSYSTEM=="thunderbolt", ATTRS{iommu_dma_protection}=="1", ATTR{authorized}=="0", ATTR{authorized}="1"

Upgrading NVM on Thunderbolt device or host
-------------------------------------------
Since most of the functionality is handled in firmware running on a
+11 −0
Original line number Diff line number Diff line
@@ -24,6 +24,14 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data,
					acpi_object_type type,
					const union acpi_object **obj);

/*
 * The GUIDs here are made equivalent to each other in order to avoid extra
 * complexity in the properties handling code, with the caveat that the
 * kernel will accept certain combinations of GUID and properties that are
 * not defined without a warning. For instance if any of the properties
 * from different GUID appear in a property list of another, it will be
 * accepted by the kernel. Firmware validation tools should catch these.
 */
static const guid_t prp_guids[] = {
	/* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
	GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c,
@@ -31,6 +39,9 @@ static const guid_t prp_guids[] = {
	/* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */
	GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3,
		  0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4),
	/* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */
	GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3,
		  0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89),
};

static const guid_t ads_guid =
+25 −0
Original line number Diff line number Diff line
@@ -2042,3 +2042,28 @@ int dmar_device_remove(acpi_handle handle)
{
	return dmar_device_hotplug(handle, false);
}

/*
 * dmar_platform_optin - Is %DMA_CTRL_PLATFORM_OPT_IN_FLAG set in DMAR table
 *
 * Returns true if the platform has %DMA_CTRL_PLATFORM_OPT_IN_FLAG set in
 * the ACPI DMAR table. This means that the platform boot firmware has made
 * sure no device can issue DMA outside of RMRR regions.
 */
bool dmar_platform_optin(void)
{
	struct acpi_table_dmar *dmar;
	acpi_status status;
	bool ret;

	status = acpi_get_table(ACPI_SIG_DMAR, 0,
				(struct acpi_table_header **)&dmar);
	if (ACPI_FAILURE(status))
		return false;

	ret = !!(dmar->flags & DMAR_PLATFORM_OPT_IN);
	acpi_put_table((struct acpi_table_header *)dmar);

	return ret;
}
EXPORT_SYMBOL_GPL(dmar_platform_optin);
+53 −3
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ static int rwbf_quirk;
 */
static int force_on = 0;
int intel_iommu_tboot_noforce;
static int no_platform_optin;

#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))

@@ -503,6 +504,7 @@ static int __init intel_iommu_setup(char *str)
			pr_info("IOMMU enabled\n");
		} else if (!strncmp(str, "off", 3)) {
			dmar_disabled = 1;
			no_platform_optin = 1;
			pr_info("IOMMU disabled\n");
		} else if (!strncmp(str, "igfx_off", 8)) {
			dmar_map_gfx = 0;
@@ -1471,7 +1473,8 @@ static void iommu_enable_dev_iotlb(struct device_domain_info *info)
	if (info->pri_supported && !pci_reset_pri(pdev) && !pci_enable_pri(pdev, 32))
		info->pri_enabled = 1;
#endif
	if (info->ats_supported && !pci_enable_ats(pdev, VTD_PAGE_SHIFT)) {
	if (!pdev->untrusted && info->ats_supported &&
	    !pci_enable_ats(pdev, VTD_PAGE_SHIFT)) {
		info->ats_enabled = 1;
		domain_update_iotlb(info->domain);
		info->ats_qdep = pci_ats_queue_depth(pdev);
@@ -2895,6 +2898,13 @@ static int iommu_should_identity_map(struct device *dev, int startup)
		if (device_is_rmrr_locked(dev))
			return 0;

		/*
		 * Prevent any device marked as untrusted from getting
		 * placed into the statically identity mapping domain.
		 */
		if (pdev->untrusted)
			return 0;

		if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
			return 1;

@@ -4728,14 +4738,54 @@ const struct attribute_group *intel_iommu_groups[] = {
	NULL,
};

static int __init platform_optin_force_iommu(void)
{
	struct pci_dev *pdev = NULL;
	bool has_untrusted_dev = false;

	if (!dmar_platform_optin() || no_platform_optin)
		return 0;

	for_each_pci_dev(pdev) {
		if (pdev->untrusted) {
			has_untrusted_dev = true;
			break;
		}
	}

	if (!has_untrusted_dev)
		return 0;

	if (no_iommu || dmar_disabled)
		pr_info("Intel-IOMMU force enabled due to platform opt in\n");

	/*
	 * If Intel-IOMMU is disabled by default, we will apply identity
	 * map for all devices except those marked as being untrusted.
	 */
	if (dmar_disabled)
		iommu_identity_mapping |= IDENTMAP_ALL;

	dmar_disabled = 0;
#if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB)
	swiotlb = 0;
#endif
	no_iommu = 0;

	return 1;
}

int __init intel_iommu_init(void)
{
	int ret = -ENODEV;
	struct dmar_drhd_unit *drhd;
	struct intel_iommu *iommu;

	/* VT-d is required for a TXT/tboot launch, so enforce that */
	force_on = tboot_force_iommu();
	/*
	 * Intel IOMMU is required for a TXT/tboot launch or platform
	 * opt in, so enforce that.
	 */
	force_on = tboot_force_iommu() || platform_optin_force_iommu();

	if (iommu_init_mempool()) {
		if (force_on)
Loading