Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86/tdx: Add device filter support for x86 TDX guest platform
For Confidential VM guests like TDX, the host is untrusted and hence the devices emulated by the host or any data coming from the host cannot be trusted. So the drivers that interact with the outside world have to be hardened and the allowed devices have to be filtered. More details about the need for device/driver filter in confidential guest can be found in article [1] titled "firewall for device drivers". So use the "authorized" device attribute to allow only the trusted list of the devices. Add support for cc_guest_authorized() which can be used by BUS drivers to consult the arch specific device allow list and initialize the "authorized" attribute. To deny all devices other than what is specified in TDX allow list, set dev_default_authorization default policy as DENY_ALL. The default audited list of drivers that a protected guest may trust are: * virtio-blk * virtio-console * virtio-net * virtio-pci * virtio_rproc_serial Add a new flag CC_ATTR_GUEST_DEVICE_FILTER to conditionally enable device filter related code in generic drivers (using cc_platform_has() API). [1] - https://lwn.net/Articles/865918/ Reviewed-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
- Loading branch information
Kuppuswamy Sathyanarayanan
committed
Sep 22, 2021
1 parent
8e9591e
commit b0040b6
Showing
8 changed files
with
209 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Copyright (c) 2020 Intel Corporation | ||
*/ | ||
#define pr_fmt(fmt) "TDX: " fmt | ||
|
||
#include <linux/acpi.h> | ||
#include <linux/pci.h> | ||
#include <linux/device.h> | ||
#include <linux/cc_platform.h> | ||
#include <linux/export.h> | ||
|
||
#include <asm/tdx.h> | ||
#include <asm/cmdline.h> | ||
|
||
/* | ||
* To support regex formats like (ALL:ALL), device allow | ||
* list uses char* type. Alternative choices like device_id | ||
* model will only add additional complexity. Using char* | ||
* will make it easier to add command line overrides. | ||
*/ | ||
struct authorize_node { | ||
const char *bus; | ||
const char *dev_list; | ||
}; | ||
|
||
/* Temporary string for storing device name */ | ||
static char dev_str[16]; | ||
|
||
/* | ||
* Allow list for PCI bus | ||
* | ||
* NOTE: Device ID is duplicated here. But for small list | ||
* of devices, it is easier to maintain the duplicated list | ||
* here verses exporting the device ID table from the driver | ||
* and use it. | ||
*/ | ||
static const char pci_allow_list[] = | ||
"0x1af4:0x1000," /* Virtio NET */ | ||
"0x1af4:0x1001," /* Virtio block */ | ||
"0x1af4:0x1003," /* Virtio console */ | ||
"0x1af4:0x1009," /* Virtio FS */ | ||
"0x1af4:0x1041," /* Virtio 1.0 NET */ | ||
"0x1af4:0x1042," /* Virtio 1.0 block */ | ||
"0x1af4:0x1043," /* Virtio 1.0 console */ | ||
"0x1af4:0x1049"; /* Virtio 1.0 FS */ | ||
|
||
static struct authorize_node allow_list[] = { | ||
/* Enable all devices in "virtio" bus */ | ||
{ "virtio", "ALL" }, | ||
/* Allow devices in pci_allow_list in "pci" bus */ | ||
{ "pci", pci_allow_list }, | ||
}; | ||
|
||
static bool authorized_node_match(struct authorize_node *node, | ||
const char *bus_name, const char *dev_list) | ||
{ | ||
const char *n; | ||
int len; | ||
|
||
/* If bus and dev_list matches "ALL", return true */ | ||
if (!strcmp(node->bus, "ALL") && !strcmp(node->dev_list, "ALL")) | ||
return true; | ||
|
||
/* | ||
* Since next step involves bus specific comparison, make | ||
* sure the bus name matches with filter node. If not | ||
* return false. | ||
*/ | ||
if (strcmp(node->bus, bus_name)) | ||
return false; | ||
|
||
/* If device name is "ALL", allow all */ | ||
if (!strcmp(node->dev_list, "ALL")) | ||
return true; | ||
|
||
for (n = node->dev_list; *n; n += len) { | ||
if (*n == ',') | ||
n++; | ||
len = strcspn(n, ","); | ||
if (!strncmp(dev_list, n, len)) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
char *get_dev_name(struct device *dev) | ||
{ | ||
struct pci_dev *pdev; | ||
|
||
/* For PCI, use format vendor:device */ | ||
if (!strncmp(dev->bus->name, "pci", 3)) { | ||
pdev = to_pci_dev(dev); | ||
sprintf(dev_str, "0x%x:0x%x", pdev->vendor, pdev->device); | ||
|
||
return dev_str; | ||
} | ||
|
||
/* For other bus, just use device name */ | ||
return (char *)dev_name(dev); | ||
} | ||
|
||
bool tdx_guest_authorized(struct device *dev) | ||
{ | ||
int i; | ||
|
||
if (!dev->bus) | ||
return dev->authorized; | ||
|
||
/* Lookup arch allow list */ | ||
for (i = 0; i < ARRAY_SIZE(allow_list); i++) { | ||
if (authorized_node_match(&allow_list[i], dev->bus->name, | ||
get_dev_name(dev))) | ||
return true; | ||
} | ||
|
||
return dev_default_authorization; | ||
} | ||
EXPORT_SYMBOL_GPL(tdx_guest_authorized); | ||
|
||
void __init tdx_filter_init(void) | ||
{ | ||
if (!cc_platform_has(CC_ATTR_GUEST_DEVICE_FILTER)) | ||
return; | ||
|
||
/* Set default authorization as disabled */ | ||
dev_default_authorization = false; | ||
|
||
pr_info("Enabled TDX guest device filter\n"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-only */ | ||
/* | ||
* Confidential Computing Device Authorization Header | ||
* | ||
* Copyright (C) 2021 Intel Corporation, Inc. | ||
* | ||
* Author: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> | ||
*/ | ||
|
||
#ifndef _CC_DEVICE_AUTHORIZED_H | ||
#define _CC_DEVICE_AUTHORIZED_H | ||
|
||
# ifndef __ASSEMBLY__ | ||
|
||
# include <linux/device.h> | ||
# include <linux/cc_platform.h> | ||
|
||
/* | ||
* cc_guest_authorized() - Used to get ARCH specific authorized status | ||
* of the given device. | ||
* @dev - device structure | ||
* | ||
* Return True to allow the device or False to deny it. | ||
* | ||
*/ | ||
|
||
# ifdef CONFIG_ARCH_HAS_CC_PLATFORM | ||
|
||
bool cc_guest_authorized(struct device *dev); | ||
|
||
# else /* !CONFIG_ARCH_HAS_CC_PLATFORM */ | ||
|
||
static inline bool cc_guest_authorized(struct device *dev) | ||
{ | ||
return dev->authorized; | ||
} | ||
|
||
# endif /* CONFIG_ARCH_HAS_CC_PLATFORM */ | ||
|
||
# endif /* __ASSEMBLY__ */ | ||
|
||
#endif /* _CC_PLATFORM_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters