1 Upstream-Status: Backport
3 Signed-off-by: Kai Kang <kai.kang@windriver.com>
5 From c25bbf1545a53ac051f9e51d4140e397660c10ae Mon Sep 17 00:00:00 2001
6 From: Jan Beulich <jbeulich@suse.com>
7 Date: Tue, 2 Jun 2015 15:07:01 +0000
8 Subject: xen/pt: unknown PCI config space fields should be read-only
9 Bug-Debian: http://bugs.debian.org/787547
11 ... by default. Add a per-device "permissive" mode similar to pciback's
12 to allow restoring previous behavior (and hence break security again,
13 i.e. should be used only for trusted guests).
15 This is part of XSA-131.
17 Signed-off-by: Jan Beulich <jbeulich@suse.com>
18 Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
19 Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>)
21 hw/xen/xen_pt.c | 32 +++++++++++++++++++++++++++++---
22 hw/xen/xen_pt.h | 2 ++
23 hw/xen/xen_pt_config_init.c | 4 ++++
24 3 files changed, 35 insertions(+), 3 deletions(-)
26 diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
27 index 8923582..9afcda8 100644
30 @@ -239,6 +239,7 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
31 XenPTReg *reg_entry = NULL;
32 uint32_t find_addr = addr;
33 XenPTRegInfo *reg = NULL;
34 + bool wp_flag = false;
36 if (xen_pt_pci_config_access_check(d, addr, len)) {
38 @@ -278,6 +279,10 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
40 /* pass directly to the real device for passthrough type register group */
41 if (reg_grp_entry == NULL) {
42 + if (!s->permissive) {
49 @@ -298,12 +303,15 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
50 uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
51 uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
52 uint8_t *ptr_val = NULL;
53 + uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
55 valid_mask <<= (find_addr - real_offset) << 3;
56 ptr_val = (uint8_t *)&val + (real_offset & 3);
57 - if (reg->emu_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
58 - wb_mask &= ~((reg->emu_mask
59 - >> ((find_addr - real_offset) << 3))
60 + if (!s->permissive) {
61 + wp_mask |= reg->res_mask;
63 + if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
64 + wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
65 << ((len - emul_len) << 3));
68 @@ -347,6 +355,16 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
70 /* nothing to do with passthrough type register,
71 * continue to find next byte */
72 + if (!s->permissive) {
73 + wb_mask &= ~(0xff << ((len - emul_len) << 3));
74 + /* Unused BARs will make it here, but we don't want to issue
75 + * warnings for writes to them (bogus writes get dealt with
85 @@ -358,6 +376,13 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
86 memory_region_transaction_commit();
89 + if (wp_flag && !s->permissive_warned) {
90 + s->permissive_warned = true;
91 + xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
92 + addr, len * 2, wb_mask);
93 + xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
94 + xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n");
96 for (index = 0; wb_mask; index += len) {
97 /* unknown regs are passed through */
98 while (!(wb_mask & 0xff)) {
99 @@ -824,6 +849,7 @@ static void xen_pt_unregister_device(PCIDevice *d)
101 static Property xen_pci_passthrough_properties[] = {
102 DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
103 + DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
104 DEFINE_PROP_END_OF_LIST(),
107 diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
108 index f9795eb..4bba559 100644
109 --- a/hw/xen/xen_pt.h
110 +++ b/hw/xen/xen_pt.h
111 @@ -197,6 +197,8 @@ struct XenPCIPassthroughState {
113 PCIHostDeviceAddress hostaddr;
116 + bool permissive_warned;
117 XenHostPCIDevice real_device;
118 XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
119 QLIST_HEAD(, XenPTRegGroup) reg_grps;
120 diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
121 index 19f926b..f3cf069 100644
122 --- a/hw/xen/xen_pt_config_init.c
123 +++ b/hw/xen/xen_pt_config_init.c
124 @@ -101,6 +101,10 @@ static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
126 uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
128 + if (!s->permissive) {
129 + throughable_mask &= ~reg->res_mask;
132 return throughable_mask & valid_mask;