Skip to content

Commit 49e00ee

Browse files
rchatreIngo Molnar
authored andcommitted
x86/intel_rdt: Fix out-of-bounds memory access in CBM tests
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 bitmap_intersects() 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 is confirmed with a KASAN test that reports: BUG: KASAN: stack-out-of-bounds in __bitmap_intersects+0xa2/0x100 and BUG: KASAN: stack-out-of-bounds in __bitmap_weight+0x58/0x90 Fix this by moving any CBM provided to a bitmap operation needing BITS_PER_LONG to an 'unsigned long' variable. [ tglx: Changed related function arguments to unsigned long and got rid of the _cbm extra step ] Fixes: 72d5050 ("x86/intel_rdt: Add utilities to test pseudo-locked region possibility") Fixes: 49f7b4e ("x86/intel_rdt: Enable setting of exclusive mode") Fixes: d9b48c8 ("x86/intel_rdt: Display resource groups' allocations' size in bytes") Fixes: 95f0b77 ("x86/intel_rdt: Initialize new resource group with sane defaults") Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: fenghua.yu@intel.com Cc: tony.luck@intel.com Cc: gavin.hindman@intel.com Cc: jithu.joseph@intel.com Cc: dave.hansen@intel.com Cc: hpa@zytor.com Link: https://lkml.kernel.org/r/69a428613a53f10e80594679ac726246020ff94f.1538686926.git.reinette.chatre@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 0238df6 commit 49e00ee

File tree

3 files changed

+37
-25
lines changed

3 files changed

+37
-25
lines changed

arch/x86/kernel/cpu/intel_rdt.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -529,14 +529,14 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
529529
int rdtgroup_schemata_show(struct kernfs_open_file *of,
530530
struct seq_file *s, void *v);
531531
bool rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d,
532-
u32 _cbm, int closid, bool exclusive);
532+
unsigned long cbm, int closid, bool exclusive);
533533
unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r, struct rdt_domain *d,
534-
u32 cbm);
534+
unsigned long cbm);
535535
enum rdtgrp_mode rdtgroup_mode_by_closid(int closid);
536536
int rdtgroup_tasks_assigned(struct rdtgroup *r);
537537
int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);
538538
int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp);
539-
bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, u32 _cbm);
539+
bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm);
540540
bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d);
541541
int rdt_pseudo_lock_init(void);
542542
void rdt_pseudo_lock_release(void);

arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -797,25 +797,27 @@ int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp)
797797
/**
798798
* rdtgroup_cbm_overlaps_pseudo_locked - Test if CBM or portion is pseudo-locked
799799
* @d: RDT domain
800-
* @_cbm: CBM to test
800+
* @cbm: CBM to test
801801
*
802-
* @d represents a cache instance and @_cbm a capacity bitmask that is
803-
* considered for it. Determine if @_cbm overlaps with any existing
802+
* @d represents a cache instance and @cbm a capacity bitmask that is
803+
* considered for it. Determine if @cbm overlaps with any existing
804804
* pseudo-locked region on @d.
805805
*
806-
* Return: true if @_cbm overlaps with pseudo-locked region on @d, false
806+
* @cbm is unsigned long, even if only 32 bits are used, to make the
807+
* bitmap functions work correctly.
808+
*
809+
* Return: true if @cbm overlaps with pseudo-locked region on @d, false
807810
* otherwise.
808811
*/
809-
bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, u32 _cbm)
812+
bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, unsigned long cbm)
810813
{
811-
unsigned long *cbm = (unsigned long *)&_cbm;
812-
unsigned long *cbm_b;
813814
unsigned int cbm_len;
815+
unsigned long cbm_b;
814816

815817
if (d->plr) {
816818
cbm_len = d->plr->r->cache.cbm_len;
817-
cbm_b = (unsigned long *)&d->plr->cbm;
818-
if (bitmap_intersects(cbm, cbm_b, cbm_len))
819+
cbm_b = d->plr->cbm;
820+
if (bitmap_intersects(&cbm, &cbm_b, cbm_len))
819821
return true;
820822
}
821823
return false;

arch/x86/kernel/cpu/intel_rdt_rdtgroup.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -975,33 +975,34 @@ static int rdtgroup_mode_show(struct kernfs_open_file *of,
975975
* is false then overlaps with any resource group or hardware entities
976976
* will be considered.
977977
*
978+
* @cbm is unsigned long, even if only 32 bits are used, to make the
979+
* bitmap functions work correctly.
980+
*
978981
* Return: false if CBM does not overlap, true if it does.
979982
*/
980983
bool rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d,
981-
u32 _cbm, int closid, bool exclusive)
984+
unsigned long cbm, int closid, bool exclusive)
982985
{
983-
unsigned long *cbm = (unsigned long *)&_cbm;
984-
unsigned long *ctrl_b;
985986
enum rdtgrp_mode mode;
987+
unsigned long ctrl_b;
986988
u32 *ctrl;
987989
int i;
988990

989991
/* Check for any overlap with regions used by hardware directly */
990992
if (!exclusive) {
991-
if (bitmap_intersects(cbm,
992-
(unsigned long *)&r->cache.shareable_bits,
993-
r->cache.cbm_len))
993+
ctrl_b = r->cache.shareable_bits;
994+
if (bitmap_intersects(&cbm, &ctrl_b, r->cache.cbm_len))
994995
return true;
995996
}
996997

997998
/* Check for overlap with other resource groups */
998999
ctrl = d->ctrl_val;
9991000
for (i = 0; i < closids_supported(); i++, ctrl++) {
1000-
ctrl_b = (unsigned long *)ctrl;
1001+
ctrl_b = *ctrl;
10011002
mode = rdtgroup_mode_by_closid(i);
10021003
if (closid_allocated(i) && i != closid &&
10031004
mode != RDT_MODE_PSEUDO_LOCKSETUP) {
1004-
if (bitmap_intersects(cbm, ctrl_b, r->cache.cbm_len)) {
1005+
if (bitmap_intersects(&cbm, &ctrl_b, r->cache.cbm_len)) {
10051006
if (exclusive) {
10061007
if (mode == RDT_MODE_EXCLUSIVE)
10071008
return true;
@@ -1138,15 +1139,18 @@ static ssize_t rdtgroup_mode_write(struct kernfs_open_file *of,
11381139
* computed by first dividing the total cache size by the CBM length to
11391140
* determine how many bytes each bit in the bitmask represents. The result
11401141
* is multiplied with the number of bits set in the bitmask.
1142+
*
1143+
* @cbm is unsigned long, even if only 32 bits are used to make the
1144+
* bitmap functions work correctly.
11411145
*/
11421146
unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r,
1143-
struct rdt_domain *d, u32 cbm)
1147+
struct rdt_domain *d, unsigned long cbm)
11441148
{
11451149
struct cpu_cacheinfo *ci;
11461150
unsigned int size = 0;
11471151
int num_b, i;
11481152

1149-
num_b = bitmap_weight((unsigned long *)&cbm, r->cache.cbm_len);
1153+
num_b = bitmap_weight(&cbm, r->cache.cbm_len);
11501154
ci = get_cpu_cacheinfo(cpumask_any(&d->cpu_mask));
11511155
for (i = 0; i < ci->num_leaves; i++) {
11521156
if (ci->info_list[i].level == r->cache_level) {
@@ -2353,6 +2357,7 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
23532357
u32 used_b = 0, unused_b = 0;
23542358
u32 closid = rdtgrp->closid;
23552359
struct rdt_resource *r;
2360+
unsigned long tmp_cbm;
23562361
enum rdtgrp_mode mode;
23572362
struct rdt_domain *d;
23582363
int i, ret;
@@ -2390,9 +2395,14 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
23902395
* modify the CBM based on system availability.
23912396
*/
23922397
cbm_ensure_valid(&d->new_ctrl, r);
2393-
if (bitmap_weight((unsigned long *) &d->new_ctrl,
2394-
r->cache.cbm_len) <
2395-
r->cache.min_cbm_bits) {
2398+
/*
2399+
* Assign the u32 CBM to an unsigned long to ensure
2400+
* that bitmap_weight() does not access out-of-bound
2401+
* memory.
2402+
*/
2403+
tmp_cbm = d->new_ctrl;
2404+
if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) <
2405+
r->cache.min_cbm_bits) {
23962406
rdt_last_cmd_printf("no space on %s:%d\n",
23972407
r->name, d->id);
23982408
return -ENOSPC;

0 commit comments

Comments
 (0)