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

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

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

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

Mike writes:

thunderbolt: Changes for v4.17 merge window

New features:

  - Intel Titan Ridge Thunderbolt 3 controller support
  - Preboot ACL supported, allowing more secure way to boot from
    Thunderbolt devices
  - New "USB only" security level

In addition there are a couple of fixes for increasing timeout when
authenticating the ICM firmware and reading root switch config space.
Preventing a crash on certain Lenovo systems where ICM firmware for some
reason is not always properly starting up.
parents f4d02909 ea9d7bb7
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
What: /sys/bus/thunderbolt/devices/.../domainX/boot_acl
Date:		Jun 2018
KernelVersion:	4.17
Contact:	thunderbolt-software@lists.01.org
Description:	Holds a comma separated list of device unique_ids that
		are allowed to be connected automatically during system
		startup (e.g boot devices). The list always contains
		maximum supported number of unique_ids where unused
		entries are empty. This allows the userspace software
		to determine how many entries the controller supports.
		If there are multiple controllers, each controller has
		its own ACL list and size may be different between the
		controllers.

		System BIOS may have an option "Preboot ACL" or similar
		that needs to be selected before this list is taken into
		consideration.

		Software always updates a full list in each write.

		If a device is authorized automatically during boot its
		boot attribute is set to 1.

What: /sys/bus/thunderbolt/devices/.../domainX/security
Date:		Sep 2017
KernelVersion:	4.13
@@ -12,6 +35,9 @@ Description: This attribute holds current Thunderbolt security level
			minimum. User needs to authorize each device.
		dponly: Automatically tunnel Display port (and USB). No
			PCIe tunnels are created.
		usbonly: Automatically tunnel USB controller of the
			 connected Thunderbolt dock (and Display Port). All
			 PCIe links downstream of the dock are removed.

What: /sys/bus/thunderbolt/devices/.../authorized
Date:		Sep 2017
@@ -38,6 +64,13 @@ Description: This attribute is used to authorize Thunderbolt devices
		   the device did not contain a key at all, and
		   EKEYREJECTED if the challenge response did not match.

What: /sys/bus/thunderbolt/devices/.../boot
Date:		Jun 2018
KernelVersion:	4.17
Contact:	thunderbolt-software@lists.01.org
Description:	This attribute contains 1 if Thunderbolt device was already
		authorized on boot and 0 otherwise.

What: /sys/bus/thunderbolt/devices/.../key
Date:		Sep 2017
KernelVersion:	4.13
+10 −5
Original line number Diff line number Diff line
@@ -21,11 +21,11 @@ vulnerable to DMA attacks.
Security levels and how to use them
-----------------------------------
Starting with Intel Falcon Ridge Thunderbolt controller there are 4
security levels available. The reason for these is the fact that the
connected devices can be DMA masters and thus read contents of the host
memory without CPU and OS knowing about it. There are ways to prevent
this by setting up an IOMMU but it is not always available for various
reasons.
security levels available. Intel Titan Ridge added one more security level
(usbonly). The reason for these is the fact that the connected devices can
be DMA masters and thus read contents of the host memory without CPU and OS
knowing about it. There are ways to prevent this by setting up an IOMMU but
it is not always available for various reasons.

The security levels are as follows:

@@ -52,6 +52,11 @@ The security levels are as follows:
    USB. No PCIe tunneling is done. In BIOS settings this is
    typically called *Display Port Only*.

  usbonly
    The firmware automatically creates tunnels for the USB controller and
    Display Port in a dock. All PCIe links downstream of the dock are
    removed.

The current security level can be read from
``/sys/bus/thunderbolt/devices/domainX/security`` where ``domainX`` is
the Thunderbolt domain the host controller manages. There is typically
+13 −15
Original line number Diff line number Diff line
@@ -170,24 +170,22 @@ static int dma_port_write(struct tb_ctl *ctl, const void *buffer, u64 route,

static int dma_find_port(struct tb_switch *sw)
{
	int port, ret;
	u32 type;
	static const int ports[] = { 3, 5, 7 };
	int i;

	/*
	 * The DMA (NHI) port is either 3 or 5 depending on the
	 * controller. Try both starting from 5 which is more common.
	 * The DMA (NHI) port is either 3, 5 or 7 depending on the
	 * controller. Try all of them.
	 */
	port = 5;
	ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), port, 2, 1,
			    DMA_PORT_TIMEOUT);
	if (!ret && (type & 0xffffff) == TB_TYPE_NHI)
		return port;
	for (i = 0; i < ARRAY_SIZE(ports); i++) {
		u32 type;
		int ret;

	port = 3;
	ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), port, 2, 1,
			    DMA_PORT_TIMEOUT);
		ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), ports[i],
				    2, 1, DMA_PORT_TIMEOUT);
		if (!ret && (type & 0xffffff) == TB_TYPE_NHI)
		return port;
			return ports[i];
	}

	return -ENODEV;
}
+129 −1
Original line number Diff line number Diff line
@@ -117,23 +117,151 @@ static const char * const tb_security_names[] = {
	[TB_SECURITY_USER] = "user",
	[TB_SECURITY_SECURE] = "secure",
	[TB_SECURITY_DPONLY] = "dponly",
	[TB_SECURITY_USBONLY] = "usbonly",
};

static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	struct tb *tb = container_of(dev, struct tb, dev);
	uuid_t *uuids;
	ssize_t ret;
	int i;

	uuids = kcalloc(tb->nboot_acl, sizeof(uuid_t), GFP_KERNEL);
	if (!uuids)
		return -ENOMEM;

	if (mutex_lock_interruptible(&tb->lock)) {
		ret = -ERESTARTSYS;
		goto out;
	}
	ret = tb->cm_ops->get_boot_acl(tb, uuids, tb->nboot_acl);
	if (ret) {
		mutex_unlock(&tb->lock);
		goto out;
	}
	mutex_unlock(&tb->lock);

	for (ret = 0, i = 0; i < tb->nboot_acl; i++) {
		if (!uuid_is_null(&uuids[i]))
			ret += snprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
					&uuids[i]);

		ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s",
			       i < tb->nboot_acl - 1 ? "," : "\n");
	}

out:
	kfree(uuids);
	return ret;
}

static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{
	struct tb *tb = container_of(dev, struct tb, dev);
	char *str, *s, *uuid_str;
	ssize_t ret = 0;
	uuid_t *acl;
	int i = 0;

	/*
	 * Make sure the value is not bigger than tb->nboot_acl * UUID
	 * length + commas and optional "\n". Also the smallest allowable
	 * string is tb->nboot_acl * ",".
	 */
	if (count > (UUID_STRING_LEN + 1) * tb->nboot_acl + 1)
		return -EINVAL;
	if (count < tb->nboot_acl - 1)
		return -EINVAL;

	str = kstrdup(buf, GFP_KERNEL);
	if (!str)
		return -ENOMEM;

	acl = kcalloc(tb->nboot_acl, sizeof(uuid_t), GFP_KERNEL);
	if (!acl) {
		ret = -ENOMEM;
		goto err_free_str;
	}

	uuid_str = strim(str);
	while ((s = strsep(&uuid_str, ",")) != NULL && i < tb->nboot_acl) {
		size_t len = strlen(s);

		if (len) {
			if (len != UUID_STRING_LEN) {
				ret = -EINVAL;
				goto err_free_acl;
			}
			ret = uuid_parse(s, &acl[i]);
			if (ret)
				goto err_free_acl;
		}

		i++;
	}

	if (s || i < tb->nboot_acl) {
		ret = -EINVAL;
		goto err_free_acl;
	}

	if (mutex_lock_interruptible(&tb->lock)) {
		ret = -ERESTARTSYS;
		goto err_free_acl;
	}
	ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl);
	mutex_unlock(&tb->lock);

err_free_acl:
	kfree(acl);
err_free_str:
	kfree(str);

	return ret ?: count;
}
static DEVICE_ATTR_RW(boot_acl);

static ssize_t security_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	struct tb *tb = container_of(dev, struct tb, dev);
	const char *name = "unknown";

	return sprintf(buf, "%s\n", tb_security_names[tb->security_level]);
	if (tb->security_level < ARRAY_SIZE(tb_security_names))
		name = tb_security_names[tb->security_level];

	return sprintf(buf, "%s\n", name);
}
static DEVICE_ATTR_RO(security);

static struct attribute *domain_attrs[] = {
	&dev_attr_boot_acl.attr,
	&dev_attr_security.attr,
	NULL,
};

static umode_t domain_attr_is_visible(struct kobject *kobj,
				      struct attribute *attr, int n)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct tb *tb = container_of(dev, struct tb, dev);

	if (attr == &dev_attr_boot_acl.attr) {
		if (tb->nboot_acl &&
		    tb->cm_ops->get_boot_acl &&
		    tb->cm_ops->set_boot_acl)
			return attr->mode;
		return 0;
	}

	return attr->mode;
}

static struct attribute_group domain_attr_group = {
	.is_visible = domain_attr_is_visible,
	.attrs = domain_attrs,
};

+685 −79

File changed.

Preview size limit exceeded, changes collapsed.

Loading