diff --git a/kernel.spec b/kernel.spec index 6a3bfbfff..515a052d9 100644 --- a/kernel.spec +++ b/kernel.spec @@ -651,6 +651,9 @@ Patch26162: Input-synaptics-remove-X1-Carbon-3rd-gen-from-the-to.patch Patch26163: Input-synaptics-remove-X250-from-the-topbuttonpad-li.patch Patch26164: Revert-Input-synaptics-use-dmax-in-input_mt_assign_s.patch +#CVE-2015-2150 rhbz 1196266 1200397 +Patch26165: xen-pciback-limit-guest-control-of-command-register.patch + # git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel Patch30000: kernel-arm64.patch @@ -1406,6 +1409,9 @@ ApplyPatch Input-synaptics-remove-X1-Carbon-3rd-gen-from-the-to.patch ApplyPatch Input-synaptics-remove-X250-from-the-topbuttonpad-li.patch ApplyPatch Revert-Input-synaptics-use-dmax-in-input_mt_assign_s.patch +#CVE-2015-2150 rhbz 1196266 1200397 +ApplyPatch xen-pciback-limit-guest-control-of-command-register.patch + %if 0%{?aarch64patches} ApplyPatch kernel-arm64.patch %ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does. @@ -2265,6 +2271,7 @@ fi %changelog * Wed Mar 11 2015 Josh Boyer - 4.0.0-0.rc3.git1.1 - Linux v4.0-rc3-111-gaffb8172de39 +- CVE-2015-2150 xen: NMIs triggerable by guests (rhbz 1196266 1200397) - Patch series to fix Lenovo *40 and Carbon X1 touchpads (rhbz 1200777 1200778) - Revert commit that added bad rpath to cpupower (rhbz 1199312) - Reenable debugging options. diff --git a/xen-pciback-limit-guest-control-of-command-register.patch b/xen-pciback-limit-guest-control-of-command-register.patch new file mode 100644 index 000000000..87600462d --- /dev/null +++ b/xen-pciback-limit-guest-control-of-command-register.patch @@ -0,0 +1,156 @@ +From: Jan Beulich +Date: Wed, 11 Mar 2015 13:51:17 +0000 +Subject: [PATCH] xen-pciback: limit guest control of command register + +Otherwise the guest can abuse that control to cause e.g. PCIe +Unsupported Request responses (by disabling memory and/or I/O decoding +and subsequently causing [CPU side] accesses to the respective address +ranges), which (depending on system configuration) may be fatal to the +host. + +Note that to alter any of the bits collected together as +PCI_COMMAND_GUEST permissive mode is now required to be enabled +globally or on the specific device. + +This is CVE-2015-2150 / XSA-120. + +Signed-off-by: Jan Beulich +Reviewed-by: Konrad Rzeszutek Wilk +--- + drivers/xen/xen-pciback/conf_space.c | 2 +- + drivers/xen/xen-pciback/conf_space.h | 2 + + drivers/xen/xen-pciback/conf_space_header.c | 61 +++++++++++++++++++++++------ + 3 files changed, 51 insertions(+), 14 deletions(-) + +diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c +index 46ae0f9f02ad..75fe3d466515 100644 +--- a/drivers/xen/xen-pciback/conf_space.c ++++ b/drivers/xen/xen-pciback/conf_space.c +@@ -16,7 +16,7 @@ + #include "conf_space.h" + #include "conf_space_quirks.h" + +-static bool permissive; ++bool permissive; + module_param(permissive, bool, 0644); + + /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, +diff --git a/drivers/xen/xen-pciback/conf_space.h b/drivers/xen/xen-pciback/conf_space.h +index e56c934ad137..2e1d73d1d5d0 100644 +--- a/drivers/xen/xen-pciback/conf_space.h ++++ b/drivers/xen/xen-pciback/conf_space.h +@@ -64,6 +64,8 @@ struct config_field_entry { + void *data; + }; + ++extern bool permissive; ++ + #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) + + /* Add fields to a device - the add_fields macro expects to get a pointer to +diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c +index c5ee82587e8c..2d7369391472 100644 +--- a/drivers/xen/xen-pciback/conf_space_header.c ++++ b/drivers/xen/xen-pciback/conf_space_header.c +@@ -11,6 +11,10 @@ + #include "pciback.h" + #include "conf_space.h" + ++struct pci_cmd_info { ++ u16 val; ++}; ++ + struct pci_bar_info { + u32 val; + u32 len_val; +@@ -20,22 +24,36 @@ struct pci_bar_info { + #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) + #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) + +-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) ++/* Bits guests are allowed to control in permissive mode. */ ++#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \ ++ PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \ ++ PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK) ++ ++static void *command_init(struct pci_dev *dev, int offset) + { +- int i; +- int ret; +- +- ret = xen_pcibk_read_config_word(dev, offset, value, data); +- if (!pci_is_enabled(dev)) +- return ret; +- +- for (i = 0; i < PCI_ROM_RESOURCE; i++) { +- if (dev->resource[i].flags & IORESOURCE_IO) +- *value |= PCI_COMMAND_IO; +- if (dev->resource[i].flags & IORESOURCE_MEM) +- *value |= PCI_COMMAND_MEMORY; ++ struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); ++ int err; ++ ++ if (!cmd) ++ return ERR_PTR(-ENOMEM); ++ ++ err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val); ++ if (err) { ++ kfree(cmd); ++ return ERR_PTR(err); + } + ++ return cmd; ++} ++ ++static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) ++{ ++ int ret = pci_read_config_word(dev, offset, value); ++ const struct pci_cmd_info *cmd = data; ++ ++ *value &= PCI_COMMAND_GUEST; ++ *value |= cmd->val & ~PCI_COMMAND_GUEST; ++ + return ret; + } + +@@ -43,6 +61,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) + { + struct xen_pcibk_dev_data *dev_data; + int err; ++ u16 val; ++ struct pci_cmd_info *cmd = data; + + dev_data = pci_get_drvdata(dev); + if (!pci_is_enabled(dev) && is_enable_cmd(value)) { +@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) + } + } + ++ cmd->val = value; ++ ++ if (!permissive && (!dev_data || !dev_data->permissive)) ++ return 0; ++ ++ /* Only allow the guest to control certain bits. */ ++ err = pci_read_config_word(dev, offset, &val); ++ if (err || val == value) ++ return err; ++ ++ value &= PCI_COMMAND_GUEST; ++ value |= val & ~PCI_COMMAND_GUEST; ++ + return pci_write_config_word(dev, offset, value); + } + +@@ -282,6 +315,8 @@ static const struct config_field header_common[] = { + { + .offset = PCI_COMMAND, + .size = 2, ++ .init = command_init, ++ .release = bar_release, + .u.w.read = command_read, + .u.w.write = command_write, + }, +-- +2.1.0 +