From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
alan@lxorguk.ukuu.org.uk, Matt Wilson <msw@amazon.com>,
Ian Campbell <Ian.Campbell@citrix.com>,
Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>,
Annie Li <annie.li@oracle.com>,
xen-devel@lists.xen.org
Subject: [ 14/21] xen/grant-table: correctly initialize grant table version 1
Date: Fri, 18 Jan 2013 17:19:32 -0800 [thread overview]
Message-ID: <20130119010713.667133748@linuxfoundation.org> (raw)
In-Reply-To: <20130119010710.897187774@linuxfoundation.org>
3.4-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Wilson <msw@amazon.com>
commit d0b4d64aadb9f4a90669848de9ef3819050a98cd upstream.
Commit 85ff6acb075a484780b3d763fdf41596d8fc0970 (xen/granttable: Grant
tables V2 implementation) changed the GREFS_PER_GRANT_FRAME macro from
a constant to a conditional expression. The expression depends on
grant_table_version being appropriately set. Unfortunately, at init
time grant_table_version will be 0. The GREFS_PER_GRANT_FRAME
conditional expression checks for "grant_table_version == 1", and
therefore returns the number of grant references per frame for v2.
This causes gnttab_init() to allocate fewer pages for gnttab_list, as
a frame can old half the number of v2 entries than v1 entries. After
gnttab_resume() is called, grant_table_version is appropriately
set. nr_init_grefs will then be miscalculated and gnttab_free_count
will hold a value larger than the actual number of free gref entries.
If a guest is heavily utilizing improperly initialized v1 grant
tables, memory corruption can occur. One common manifestation is
corruption of the vmalloc list, resulting in a poisoned pointer
derefrence when accessing /proc/meminfo or /proc/vmallocinfo:
[ 40.770064] BUG: unable to handle kernel paging request at 0000200200001407
[ 40.770083] IP: [<ffffffff811a6fb0>] get_vmalloc_info+0x70/0x110
[ 40.770102] PGD 0
[ 40.770107] Oops: 0000 [#1] SMP
[ 40.770114] CPU 10
This patch introduces a static variable, grefs_per_grant_frame, to
cache the calculated value. gnttab_init() now calls
gnttab_request_version() early so that grant_table_version and
grefs_per_grant_frame can be appropriately set. A few BUG_ON()s have
been added to prevent this type of bug from reoccurring in the future.
Signed-off-by: Matt Wilson <msw@amazon.com>
Reviewed-and-Tested-by: Steven Noonan <snoonan@amazon.com>
Acked-by: Ian Campbell <Ian.Campbell@citrix.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Annie Li <annie.li@oracle.com>
Cc: xen-devel@lists.xen.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/xen/grant-table.c | 48 +++++++++++++++++++++++++++-------------------
1 file changed, 29 insertions(+), 19 deletions(-)
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -53,10 +53,6 @@
/* External tools reserve first few grant table entries. */
#define NR_RESERVED_ENTRIES 8
#define GNTTAB_LIST_END 0xffffffff
-#define GREFS_PER_GRANT_FRAME \
-(grant_table_version == 1 ? \
-(PAGE_SIZE / sizeof(struct grant_entry_v1)) : \
-(PAGE_SIZE / sizeof(union grant_entry_v2)))
static grant_ref_t **gnttab_list;
static unsigned int nr_grant_frames;
@@ -151,6 +147,7 @@ static struct gnttab_ops *gnttab_interfa
static grant_status_t *grstatus;
static int grant_table_version;
+static int grefs_per_grant_frame;
static struct gnttab_free_callback *gnttab_free_callback_list;
@@ -679,12 +676,14 @@ static int grow_gnttab_list(unsigned int
unsigned int new_nr_grant_frames, extra_entries, i;
unsigned int nr_glist_frames, new_nr_glist_frames;
+ BUG_ON(grefs_per_grant_frame == 0);
+
new_nr_grant_frames = nr_grant_frames + more_frames;
- extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
+ extra_entries = more_frames * grefs_per_grant_frame;
- nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
+ nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP;
new_nr_glist_frames =
- (new_nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
+ (new_nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP;
for (i = nr_glist_frames; i < new_nr_glist_frames; i++) {
gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
if (!gnttab_list[i])
@@ -692,12 +691,12 @@ static int grow_gnttab_list(unsigned int
}
- for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
- i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+ for (i = grefs_per_grant_frame * nr_grant_frames;
+ i < grefs_per_grant_frame * new_nr_grant_frames - 1; i++)
gnttab_entry(i) = i + 1;
gnttab_entry(i) = gnttab_free_head;
- gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ gnttab_free_head = grefs_per_grant_frame * nr_grant_frames;
gnttab_free_count += extra_entries;
nr_grant_frames = new_nr_grant_frames;
@@ -799,7 +798,8 @@ EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
static unsigned nr_status_frames(unsigned nr_grant_frames)
{
- return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP;
+ BUG_ON(grefs_per_grant_frame == 0);
+ return (nr_grant_frames * grefs_per_grant_frame + SPP - 1) / SPP;
}
static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes)
@@ -957,6 +957,7 @@ static void gnttab_request_version(void)
rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
if (rc == 0 && gsv.version == 2) {
grant_table_version = 2;
+ grefs_per_grant_frame = PAGE_SIZE / sizeof(union grant_entry_v2);
gnttab_interface = &gnttab_v2_ops;
} else if (grant_table_version == 2) {
/*
@@ -969,17 +970,17 @@ static void gnttab_request_version(void)
panic("we need grant tables version 2, but only version 1 is available");
} else {
grant_table_version = 1;
+ grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1);
gnttab_interface = &gnttab_v1_ops;
}
printk(KERN_INFO "Grant tables using version %d layout.\n",
grant_table_version);
}
-int gnttab_resume(void)
+static int gnttab_setup(void)
{
unsigned int max_nr_gframes;
- gnttab_request_version();
max_nr_gframes = gnttab_max_grant_frames();
if (max_nr_gframes < nr_grant_frames)
return -ENOSYS;
@@ -1002,6 +1003,12 @@ int gnttab_resume(void)
return 0;
}
+int gnttab_resume(void)
+{
+ gnttab_request_version();
+ return gnttab_setup();
+}
+
int gnttab_suspend(void)
{
gnttab_interface->unmap_frames();
@@ -1013,9 +1020,10 @@ static int gnttab_expand(unsigned int re
int rc;
unsigned int cur, extra;
+ BUG_ON(grefs_per_grant_frame == 0);
cur = nr_grant_frames;
- extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
- GREFS_PER_GRANT_FRAME);
+ extra = ((req_entries + (grefs_per_grant_frame-1)) /
+ grefs_per_grant_frame);
if (cur + extra > gnttab_max_grant_frames())
return -ENOSPC;
@@ -1033,21 +1041,23 @@ int gnttab_init(void)
unsigned int nr_init_grefs;
int ret;
+ gnttab_request_version();
nr_grant_frames = 1;
boot_max_nr_grant_frames = __max_nr_grant_frames();
/* Determine the maximum number of frames required for the
* grant reference free list on the current hypervisor.
*/
+ BUG_ON(grefs_per_grant_frame == 0);
max_nr_glist_frames = (boot_max_nr_grant_frames *
- GREFS_PER_GRANT_FRAME / RPP);
+ grefs_per_grant_frame / RPP);
gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
GFP_KERNEL);
if (gnttab_list == NULL)
return -ENOMEM;
- nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
+ nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP;
for (i = 0; i < nr_glist_frames; i++) {
gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
if (gnttab_list[i] == NULL) {
@@ -1056,12 +1066,12 @@ int gnttab_init(void)
}
}
- if (gnttab_resume() < 0) {
+ if (gnttab_setup() < 0) {
ret = -ENODEV;
goto ini_nomem;
}
- nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+ nr_init_grefs = nr_grant_frames * grefs_per_grant_frame;
for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
gnttab_entry(i) = i + 1;
next prev parent reply other threads:[~2013-01-19 1:21 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-19 1:19 [ 00/21] 3.4.27-stable review Greg Kroah-Hartman
2013-01-19 1:19 ` [ 01/21] sh: Fix FDPIC binary loader Greg Kroah-Hartman
2013-01-19 1:19 ` [ 02/21] tcm_fc: Do not indicate retry capability to initiators Greg Kroah-Hartman
2013-01-19 1:19 ` [ 03/21] tcm_fc: Do not report target role when target is not defined Greg Kroah-Hartman
2013-01-19 1:19 ` [ 04/21] target: Release se_cmd when LUN lookup fails for TMR Greg Kroah-Hartman
2013-01-19 1:19 ` [ 05/21] s390/time: fix sched_clock() overflow Greg Kroah-Hartman
2013-01-19 1:19 ` [ 06/21] x86/Sandy Bridge: reserve pages when integrated graphics is present Greg Kroah-Hartman
2013-01-19 1:19 ` [ 07/21] ALSA: usb - fix race in creation of M-Audio Fast track pro driver Greg Kroah-Hartman
2013-01-19 1:19 ` [ 08/21] ext4: init pagevec in ext4_da_block_invalidatepages Greg Kroah-Hartman
2013-01-19 1:19 ` [ 09/21] r8169: avoid NAPI scheduling delay Greg Kroah-Hartman
2013-01-19 1:19 ` [ 10/21] target: Add link_magic for fabric allow_link destination target_items Greg Kroah-Hartman
2013-01-19 4:13 ` Ben Hutchings
2013-01-19 1:19 ` [ 11/21] intel-iommu: Prevent devices with RMRRs from being placed into SI Domain Greg Kroah-Hartman
2013-01-19 1:19 ` [ 12/21] igb: release already assigned MSI-X interrupts if setup fails Greg Kroah-Hartman
2013-01-19 1:19 ` [ 13/21] drbd: add missing part_round_stats to _drbd_start_io_acct Greg Kroah-Hartman
2013-01-19 1:19 ` Greg Kroah-Hartman [this message]
2013-01-19 1:19 ` [ 15/21] xen: Fix stack corruption in xen_failsafe_callback for 32bit PVOPS guests Greg Kroah-Hartman
2013-01-19 1:19 ` [ 16/21] USB: option: add TP-LINK HSUPA Modem MA180 Greg Kroah-Hartman
2013-01-19 1:19 ` [ 17/21] USB: option: blacklist network interface on ONDA MT8205 4G LTE Greg Kroah-Hartman
2013-01-19 1:19 ` [ 18/21] serial:ifx6x60:Delete SPI timer when shut down port Greg Kroah-Hartman
2013-01-19 1:19 ` [ 19/21] tty: 8250_dw: Fix inverted arguments to serial_out in IRQ handler Greg Kroah-Hartman
2013-01-19 1:19 ` [ 20/21] staging: wlan-ng: Fix clamping of returned SSID length Greg Kroah-Hartman
2013-01-19 1:19 ` [ 21/21] staging: vt6656: Fix inconsistent structure packing Greg Kroah-Hartman
2013-01-19 18:51 ` [ 00/21] 3.4.27-stable review Shuah Khan
2013-01-20 9:04 ` Satoru Takeuchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130119010713.667133748@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=Ian.Campbell@citrix.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=annie.li@oracle.com \
--cc=konrad.wilk@oracle.com \
--cc=linux-kernel@vger.kernel.org \
--cc=msw@amazon.com \
--cc=stable@vger.kernel.org \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.