system/xen: XSA 231-235 update.

Signed-off-by: Mario Preksavec <mario@slackware.hr>
This commit is contained in:
Mario Preksavec 2017-09-18 23:05:24 +02:00 committed by David Spencer
parent c9bcfd5b7d
commit 0738227939
10 changed files with 429 additions and 5 deletions

View file

@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 4.4.75 Kernel Configuration
# Linux/x86 4.4.88 Kernel Configuration
#
# CONFIG_64BIT is not set
CONFIG_X86_32=y

View file

@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 4.4.75 Kernel Configuration
# Linux/x86 4.4.88 Kernel Configuration
#
CONFIG_64BIT=y
CONFIG_X86_64=y

View file

@ -5,7 +5,7 @@
# Written by Chris Abela <chris.abela@maltats.com>, 20100515
# Modified by Mario Preksavec <mario@slackware.hr>
KERNEL=${KERNEL:-4.4.75}
KERNEL=${KERNEL:-4.4.88}
XEN=${XEN:-4.9.0}
BOOTLOADER=${BOOTLOADER:-lilo}

View file

@ -7,7 +7,7 @@
set -e
KERNEL=${KERNEL:-4.4.75}
KERNEL=${KERNEL:-4.4.88}
# Build an image for the root file system and another for the swap
# Default values : 8GB and 500MB resepectively.

View file

@ -24,7 +24,7 @@
PRGNAM=xen
VERSION=${VERSION:-4.9.0}
BUILD=${BUILD:-2}
BUILD=${BUILD:-3}
TAG=${TAG:-_SBo}
SEABIOS=${SEABIOS:-1.10.0}

View file

@ -0,0 +1,108 @@
From: George Dunlap <george.dunlap@citrix.com>
Subject: xen/mm: make sure node is less than MAX_NUMNODES
The output of MEMF_get_node(memflags) can be as large as nodeid_t can
hold (currently 255). This is then used as an index to arrays of size
MAX_NUMNODE, which is 64 on x86 and 1 on ARM, can be passed in by an
untrusted guest (via memory_exchange and increase_reservation) and is
not currently bounds-checked.
Check the value in page_alloc.c before using it, and also check the
value in the hypercall call sites and return -EINVAL if appropriate.
Don't permit domains other than the hardware or control domain to
allocate node-constrained memory.
This is XSA-231.
Reported-by: Matthew Daley <mattd@bugfuzz.com>
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -411,6 +411,31 @@ static void decrease_reservation(struct
a->nr_done = i;
}
+static bool propagate_node(unsigned int xmf, unsigned int *memflags)
+{
+ const struct domain *currd = current->domain;
+
+ BUILD_BUG_ON(XENMEMF_get_node(0) != NUMA_NO_NODE);
+ BUILD_BUG_ON(MEMF_get_node(0) != NUMA_NO_NODE);
+
+ if ( XENMEMF_get_node(xmf) == NUMA_NO_NODE )
+ return true;
+
+ if ( is_hardware_domain(currd) || is_control_domain(currd) )
+ {
+ if ( XENMEMF_get_node(xmf) >= MAX_NUMNODES )
+ return false;
+
+ *memflags |= MEMF_node(XENMEMF_get_node(xmf));
+ if ( xmf & XENMEMF_exact_node_request )
+ *memflags |= MEMF_exact_node;
+ }
+ else if ( xmf & XENMEMF_exact_node_request )
+ return false;
+
+ return true;
+}
+
static long memory_exchange(XEN_GUEST_HANDLE_PARAM(xen_memory_exchange_t) arg)
{
struct xen_memory_exchange exch;
@@ -483,6 +508,12 @@ static long memory_exchange(XEN_GUEST_HA
}
}
+ if ( unlikely(!propagate_node(exch.out.mem_flags, &memflags)) )
+ {
+ rc = -EINVAL;
+ goto fail_early;
+ }
+
d = rcu_lock_domain_by_any_id(exch.in.domid);
if ( d == NULL )
{
@@ -501,7 +532,6 @@ static long memory_exchange(XEN_GUEST_HA
d,
XENMEMF_get_address_bits(exch.out.mem_flags) ? :
(BITS_PER_LONG+PAGE_SHIFT)));
- memflags |= MEMF_node(XENMEMF_get_node(exch.out.mem_flags));
for ( i = (exch.nr_exchanged >> in_chunk_order);
i < (exch.in.nr_extents >> in_chunk_order);
@@ -864,12 +894,8 @@ static int construct_memop_from_reservat
}
read_unlock(&d->vnuma_rwlock);
}
- else
- {
- a->memflags |= MEMF_node(XENMEMF_get_node(r->mem_flags));
- if ( r->mem_flags & XENMEMF_exact_node_request )
- a->memflags |= MEMF_exact_node;
- }
+ else if ( unlikely(!propagate_node(r->mem_flags, &a->memflags)) )
+ return -EINVAL;
return 0;
}
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -706,9 +706,13 @@ static struct page_info *alloc_heap_page
if ( node >= MAX_NUMNODES )
node = cpu_to_node(smp_processor_id());
}
+ else if ( unlikely(node >= MAX_NUMNODES) )
+ {
+ ASSERT_UNREACHABLE();
+ return NULL;
+ }
first_node = node;
- ASSERT(node < MAX_NUMNODES);
ASSERT(zone_lo <= zone_hi);
ASSERT(zone_hi < NR_ZONES);

View file

@ -0,0 +1,23 @@
From: Andrew Cooper <andrew.cooper3@citrix.com>
Subject: grant_table: fix GNTTABOP_cache_flush handling
Don't fall over a NULL grant_table pointer when the owner of the domain
is a system domain (DOMID_{XEN,IO} etc).
This is XSA-232.
Reported-by: Matthew Daley <mattd@bugfuzz.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -3053,7 +3053,7 @@ static int cache_flush(gnttab_cache_flus
page = mfn_to_page(mfn);
owner = page_get_owner_and_reference(page);
- if ( !owner )
+ if ( !owner || !owner->grant_table )
{
rcu_unlock_domain(d);
return -EPERM;

View file

@ -0,0 +1,52 @@
From: Juergen Gross <jgross@suse.com>
Subject: tools/xenstore: dont unlink connection object twice
A connection object of a domain with associated stubdom has two
parents: the domain and the stubdom. When cleaning up the list of
active domains in domain_cleanup() make sure not to unlink the
connection twice from the same domain. This could happen when the
domain and its stubdom are being destroyed at the same time leading
to the domain loop being entered twice.
Additionally don't use talloc_free() in this case as it will remove
a random parent link, leading eventually to a memory leak. Use
talloc_unlink() instead specifying the context from which the
connection object should be removed.
This is XSA-233.
Reported-by: Eric Chanudet <chanudete@ainfosec.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Ian Jackson <ian.jackson@eu.citrix.com>
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -221,10 +221,11 @@ static int destroy_domain(void *_domain)
static void domain_cleanup(void)
{
xc_dominfo_t dominfo;
- struct domain *domain, *tmp;
+ struct domain *domain;
int notify = 0;
- list_for_each_entry_safe(domain, tmp, &domains, list) {
+ again:
+ list_for_each_entry(domain, &domains, list) {
if (xc_domain_getinfo(*xc_handle, domain->domid, 1,
&dominfo) == 1 &&
dominfo.domid == domain->domid) {
@@ -236,8 +237,12 @@ static void domain_cleanup(void)
if (!dominfo.dying)
continue;
}
- talloc_free(domain->conn);
- notify = 0; /* destroy_domain() fires the watch */
+ if (domain->conn) {
+ talloc_unlink(talloc_autofree_context(), domain->conn);
+ domain->conn = NULL;
+ notify = 0; /* destroy_domain() fires the watch */
+ goto again;
+ }
}
if (notify)

View file

@ -0,0 +1,192 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: gnttab: also validate PTE permissions upon destroy/replace
In order for PTE handling to match up with the reference counting done
by common code, presence and writability of grant mapping PTEs must
also be taken into account; validating just the frame number is not
enough. This is in particular relevant if a guest fiddles with grant
PTEs via non-grant hypercalls.
Note that the flags being passed to replace_grant_host_mapping()
already happen to be those of the existing mapping, so no new function
parameter is needed.
This is XSA-234.
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -4058,7 +4058,8 @@ static int create_grant_pte_mapping(
}
static int destroy_grant_pte_mapping(
- uint64_t addr, unsigned long frame, struct domain *d)
+ uint64_t addr, unsigned long frame, unsigned int grant_pte_flags,
+ struct domain *d)
{
int rc = GNTST_okay;
void *va;
@@ -4104,17 +4105,29 @@ static int destroy_grant_pte_mapping(
ol1e = *(l1_pgentry_t *)va;
- /* Check that the virtual address supplied is actually mapped to frame. */
- if ( unlikely(l1e_get_pfn(ol1e) != frame) )
+ /*
+ * Check that the PTE supplied actually maps frame (with appropriate
+ * permissions).
+ */
+ if ( unlikely(l1e_get_pfn(ol1e) != frame) ||
+ unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) &
+ (_PAGE_PRESENT | _PAGE_RW)) )
{
page_unlock(page);
- gdprintk(XENLOG_WARNING,
- "PTE entry %"PRIpte" for address %"PRIx64" doesn't match frame %lx\n",
- l1e_get_intpte(ol1e), addr, frame);
+ gdprintk(XENLOG_ERR,
+ "PTE %"PRIpte" at %"PRIx64" doesn't match grant (%"PRIpte")\n",
+ l1e_get_intpte(ol1e), addr,
+ l1e_get_intpte(l1e_from_pfn(frame, grant_pte_flags)));
rc = GNTST_general_error;
goto failed;
}
+ if ( unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) &
+ ~(_PAGE_AVAIL | PAGE_CACHE_ATTRS)) )
+ gdprintk(XENLOG_WARNING,
+ "PTE flags %x at %"PRIx64" don't match grant (%x)\n",
+ l1e_get_flags(ol1e), addr, grant_pte_flags);
+
/* Delete pagetable entry. */
if ( unlikely(!UPDATE_ENTRY
(l1,
@@ -4123,7 +4136,8 @@ static int destroy_grant_pte_mapping(
0)) )
{
page_unlock(page);
- gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", va);
+ gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %"PRIx64"\n",
+ addr);
rc = GNTST_general_error;
goto failed;
}
@@ -4191,7 +4205,8 @@ static int create_grant_va_mapping(
}
static int replace_grant_va_mapping(
- unsigned long addr, unsigned long frame, l1_pgentry_t nl1e, struct vcpu *v)
+ unsigned long addr, unsigned long frame, unsigned int grant_pte_flags,
+ l1_pgentry_t nl1e, struct vcpu *v)
{
l1_pgentry_t *pl1e, ol1e;
unsigned long gl1mfn;
@@ -4227,20 +4242,33 @@ static int replace_grant_va_mapping(
ol1e = *pl1e;
- /* Check that the virtual address supplied is actually mapped to frame. */
- if ( unlikely(l1e_get_pfn(ol1e) != frame) )
- {
- gdprintk(XENLOG_WARNING,
- "PTE entry %lx for address %lx doesn't match frame %lx\n",
- l1e_get_pfn(ol1e), addr, frame);
+ /*
+ * Check that the virtual address supplied is actually mapped to frame
+ * (with appropriate permissions).
+ */
+ if ( unlikely(l1e_get_pfn(ol1e) != frame) ||
+ unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) &
+ (_PAGE_PRESENT | _PAGE_RW)) )
+ {
+ gdprintk(XENLOG_ERR,
+ "PTE %"PRIpte" for %lx doesn't match grant (%"PRIpte")\n",
+ l1e_get_intpte(ol1e), addr,
+ l1e_get_intpte(l1e_from_pfn(frame, grant_pte_flags)));
rc = GNTST_general_error;
goto unlock_and_out;
}
+ if ( unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) &
+ ~(_PAGE_AVAIL | PAGE_CACHE_ATTRS)) )
+ gdprintk(XENLOG_WARNING,
+ "PTE flags %x for %"PRIx64" don't match grant (%x)\n",
+ l1e_get_flags(ol1e), addr, grant_pte_flags);
+
/* Delete pagetable entry. */
if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0)) )
{
- gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", pl1e);
+ gdprintk(XENLOG_WARNING, "Cannot delete PTE entry for %"PRIx64"\n",
+ addr);
rc = GNTST_general_error;
goto unlock_and_out;
}
@@ -4254,9 +4282,11 @@ static int replace_grant_va_mapping(
}
static int destroy_grant_va_mapping(
- unsigned long addr, unsigned long frame, struct vcpu *v)
+ unsigned long addr, unsigned long frame, unsigned int grant_pte_flags,
+ struct vcpu *v)
{
- return replace_grant_va_mapping(addr, frame, l1e_empty(), v);
+ return replace_grant_va_mapping(addr, frame, grant_pte_flags,
+ l1e_empty(), v);
}
static int create_grant_p2m_mapping(uint64_t addr, unsigned long frame,
@@ -4351,20 +4381,39 @@ int replace_grant_host_mapping(
unsigned long gl1mfn;
struct page_info *l1pg;
int rc;
+ unsigned int grant_pte_flags;
if ( paging_mode_external(current->domain) )
return replace_grant_p2m_mapping(addr, frame, new_addr, flags);
+ grant_pte_flags =
+ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_GNTTAB | _PAGE_NX;
+
+ if ( flags & GNTMAP_application_map )
+ grant_pte_flags |= _PAGE_USER;
+ if ( !(flags & GNTMAP_readonly) )
+ grant_pte_flags |= _PAGE_RW;
+ /*
+ * On top of the explicit settings done by create_grant_host_mapping()
+ * also open-code relevant parts of adjust_guest_l1e(). Don't mirror
+ * available and cachability flags, though.
+ */
+ if ( !is_pv_32bit_domain(curr->domain) )
+ grant_pte_flags |= (grant_pte_flags & _PAGE_USER)
+ ? _PAGE_GLOBAL
+ : _PAGE_GUEST_KERNEL | _PAGE_USER;
+
if ( flags & GNTMAP_contains_pte )
{
if ( !new_addr )
- return destroy_grant_pte_mapping(addr, frame, curr->domain);
+ return destroy_grant_pte_mapping(addr, frame, grant_pte_flags,
+ curr->domain);
return GNTST_general_error;
}
if ( !new_addr )
- return destroy_grant_va_mapping(addr, frame, curr);
+ return destroy_grant_va_mapping(addr, frame, grant_pte_flags, curr);
pl1e = guest_map_l1e(new_addr, &gl1mfn);
if ( !pl1e )
@@ -4412,7 +4461,7 @@ int replace_grant_host_mapping(
put_page(l1pg);
guest_unmap_l1e(pl1e);
- rc = replace_grant_va_mapping(addr, frame, ol1e, curr);
+ rc = replace_grant_va_mapping(addr, frame, grant_pte_flags, ol1e, curr);
if ( rc && !paging_mode_refcounts(curr->domain) )
put_page_from_l1e(ol1e, curr->domain);

View file

@ -0,0 +1,49 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: arm/mm: release grant lock on xenmem_add_to_physmap_one() error paths
Commit 55021ff9ab ("xen/arm: add_to_physmap_one: Avoid to map mfn 0 if
an error occurs") introduced error paths not releasing the grant table
lock. Replace them by a suitable check after the lock was dropped.
This is XSA-235.
Reported-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1164,7 +1164,7 @@ int xenmem_add_to_physmap_one(
if ( idx < nr_status_frames(d->grant_table) )
mfn = virt_to_mfn(d->grant_table->status[idx]);
else
- return -EINVAL;
+ mfn = mfn_x(INVALID_MFN);
}
else
{
@@ -1175,14 +1175,21 @@ int xenmem_add_to_physmap_one(
if ( idx < nr_grant_frames(d->grant_table) )
mfn = virt_to_mfn(d->grant_table->shared_raw[idx]);
else
- return -EINVAL;
+ mfn = mfn_x(INVALID_MFN);
}
- d->arch.grant_table_gfn[idx] = gfn;
+ if ( mfn != mfn_x(INVALID_MFN) )
+ {
+ d->arch.grant_table_gfn[idx] = gfn;
- t = p2m_ram_rw;
+ t = p2m_ram_rw;
+ }
grant_write_unlock(d->grant_table);
+
+ if ( mfn == mfn_x(INVALID_MFN) )
+ return -EINVAL;
+
break;
case XENMAPSPACE_shared_info:
if ( idx != 0 )