Commit 32f010de authored by Reinette Chatre's avatar Reinette Chatre Committed by Borislav Petkov

x86/resctrl: Prevent possible overrun during bitmap operations

While the DOC at the beginning of lib/bitmap.c explicitly states that
"The number of valid bits in a given bitmap does _not_ need to be an
exact multiple of BITS_PER_LONG.", some of the bitmap operations do
indeed access BITS_PER_LONG portions of the provided bitmap no matter
the size of the provided bitmap.

For example, if find_first_bit() is provided with an 8 bit bitmap the
operation will access BITS_PER_LONG bits from the provided bitmap. While
the operation ensures that these extra bits do not affect the result,
the memory is still accessed.

The capacity bitmasks (CBMs) are typically stored in u32 since they
can never exceed 32 bits. A few instances exist where a bitmap_*
operation is performed on a CBM by simply pointing the bitmap operation
to the stored u32 value.

The consequence of this pattern is that some bitmap_* operations will
access out-of-bounds memory when interacting with the provided CBM.

This same issue has previously been addressed with commit 49e00eee
("x86/intel_rdt: Fix out-of-bounds memory access in CBM tests")
but at that time not all instances of the issue were fixed.

Fix this by using an unsigned long to store the capacity bitmask data
that is passed to bitmap functions.

Fixes: e6519011 ("x86/intel_rdt: Introduce "bit_usage" to display cache allocations details")
Fixes: f4e80d67 ("x86/intel_rdt: Resctrl files reflect pseudo-locked information")
Fixes: 95f0b77e ("x86/intel_rdt: Initialize new resource group with sane defaults")
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: stable <stable@vger.kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: x86-ml <x86@kernel.org>
Link: https://lkml.kernel.org/r/58c9b6081fd9bf599af0dfc01a6fdd335768efef.1560975645.git.reinette.chatre@intel.com
parent 5423f5ce
...@@ -804,8 +804,12 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, ...@@ -804,8 +804,12 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
struct seq_file *seq, void *v) struct seq_file *seq, void *v)
{ {
struct rdt_resource *r = of->kn->parent->priv; struct rdt_resource *r = of->kn->parent->priv;
u32 sw_shareable = 0, hw_shareable = 0; /*
u32 exclusive = 0, pseudo_locked = 0; * Use unsigned long even though only 32 bits are used to ensure
* test_bit() is used safely.
*/
unsigned long sw_shareable = 0, hw_shareable = 0;
unsigned long exclusive = 0, pseudo_locked = 0;
struct rdt_domain *dom; struct rdt_domain *dom;
int i, hwb, swb, excl, psl; int i, hwb, swb, excl, psl;
enum rdtgrp_mode mode; enum rdtgrp_mode mode;
...@@ -850,10 +854,10 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, ...@@ -850,10 +854,10 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
} }
for (i = r->cache.cbm_len - 1; i >= 0; i--) { for (i = r->cache.cbm_len - 1; i >= 0; i--) {
pseudo_locked = dom->plr ? dom->plr->cbm : 0; pseudo_locked = dom->plr ? dom->plr->cbm : 0;
hwb = test_bit(i, (unsigned long *)&hw_shareable); hwb = test_bit(i, &hw_shareable);
swb = test_bit(i, (unsigned long *)&sw_shareable); swb = test_bit(i, &sw_shareable);
excl = test_bit(i, (unsigned long *)&exclusive); excl = test_bit(i, &exclusive);
psl = test_bit(i, (unsigned long *)&pseudo_locked); psl = test_bit(i, &pseudo_locked);
if (hwb && swb) if (hwb && swb)
seq_putc(seq, 'X'); seq_putc(seq, 'X');
else if (hwb && !swb) else if (hwb && !swb)
...@@ -2494,26 +2498,19 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn, ...@@ -2494,26 +2498,19 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn,
*/ */
static void cbm_ensure_valid(u32 *_val, struct rdt_resource *r) static void cbm_ensure_valid(u32 *_val, struct rdt_resource *r)
{ {
/* unsigned long val = *_val;
* Convert the u32 _val to an unsigned long required by all the bit
* operations within this function. No more than 32 bits of this
* converted value can be accessed because all bit operations are
* additionally provided with cbm_len that is initialized during
* hardware enumeration using five bits from the EAX register and
* thus never can exceed 32 bits.
*/
unsigned long *val = (unsigned long *)_val;
unsigned int cbm_len = r->cache.cbm_len; unsigned int cbm_len = r->cache.cbm_len;
unsigned long first_bit, zero_bit; unsigned long first_bit, zero_bit;
if (*val == 0) if (val == 0)
return; return;
first_bit = find_first_bit(val, cbm_len); first_bit = find_first_bit(&val, cbm_len);
zero_bit = find_next_zero_bit(val, cbm_len, first_bit); zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
/* Clear any remaining bits to ensure contiguous region */ /* Clear any remaining bits to ensure contiguous region */
bitmap_clear(val, zero_bit, cbm_len - zero_bit); bitmap_clear(&val, zero_bit, cbm_len - zero_bit);
*_val = (u32)val;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment