Skip to content

Commit

Permalink
Fix to prevent a possible invocation-time error on Linux 3.7 and
Browse files Browse the repository at this point in the history
later kernels configured with CONFIG_SLAB, running against vmcore
files filtered with the makedumpfile(8) facility.  Without the
patch, the message "crash: page excluded: kernel virtual address:
<address>  type: kmem_cache buffer" is immediately followed by
the message "crash: unable to initialize kmem slab cache subsystem".
Because of a kernel data structure name change from "cache_cache" to
"kmem_cache_boot", the crash utility failed to properly downsize
the stored size of the kernel's kmem_cache data structure from the
size indicated by the vmlinux debuginfo data.  This in turn could
lead to reading beyond the end of a kmem_cache data structure into
a page of memory that had been excluded from the vmcore.  The fix
was also applied to kernels configured with CONFIG_SLUB.
(anderson@redhat.com)
  • Loading branch information
Dave Anderson committed Feb 20, 2014
1 parent 51f0a17 commit c0b7a74
Showing 1 changed file with 52 additions and 9 deletions.
61 changes: 52 additions & 9 deletions memory.c
Expand Up @@ -8677,21 +8677,61 @@ static void
kmem_cache_downsize(void)
{
char *cache_buf;
uint buffer_size;
ulong kmem_cache;
uint buffer_size, object_size;
int nr_node_ids;
int nr_cpu_ids;

if (vt->flags & KMALLOC_SLUB) {
if (kernel_symbol_exists("kmem_cache") &&
VALID_MEMBER(kmem_cache_objsize) &&
try_get_symbol_data("kmem_cache",
sizeof(ulong), &kmem_cache) &&
readmem(kmem_cache + OFFSET(kmem_cache_objsize),
KVADDR, &object_size, sizeof(int),
"kmem_cache objsize/object_size", RETURN_ON_ERROR)) {
ASSIGN_SIZE(kmem_cache) = object_size;
if (CRASHDEBUG(1))
fprintf(fp, "\nkmem_cache_downsize: %ld to %ld\n",
STRUCT_SIZE("kmem_cache"),
SIZE(kmem_cache));
}
return;
}

if ((THIS_KERNEL_VERSION < LINUX(2,6,22)) ||
!(vt->flags & PERCPU_KMALLOC_V2_NODES) ||
!kernel_symbol_exists("cache_cache") ||
(!kernel_symbol_exists("cache_cache") &&
!kernel_symbol_exists("kmem_cache_boot")) ||
(!MEMBER_EXISTS("kmem_cache", "buffer_size") &&
!MEMBER_EXISTS("kmem_cache", "size"))) {
return;
}

if (vt->flags & NODELISTS_IS_PTR) {
/*
* kmem_cache.array[] is actually sized by
* More recent kernels have kmem_cache.array[] sized
* by the number of cpus plus the number of nodes.
*/
if (kernel_symbol_exists("kmem_cache_boot") &&
MEMBER_EXISTS("kmem_cache", "object_size") &&
readmem(symbol_value("kmem_cache_boot") +
MEMBER_OFFSET("kmem_cache", "object_size"),
KVADDR, &object_size, sizeof(int),
"kmem_cache_boot object_size", RETURN_ON_ERROR))
ASSIGN_SIZE(kmem_cache_s) = object_size;
else if (kernel_symbol_exists("cache_cache") &&
MEMBER_EXISTS("kmem_cache", "object_size") &&
readmem(symbol_value("cache_cache") +
MEMBER_OFFSET("kmem_cache", "object_size"),
KVADDR, &object_size, sizeof(int),
"cache_cache object_size", RETURN_ON_ERROR))
ASSIGN_SIZE(kmem_cache_s) = object_size;
else
object_size = 0;

/*
* Older kernels have kmem_cache.array[] sized by
* the number of cpus; real value is nr_cpu_ids,
* but fallback is kt->cpus.
*/
Expand All @@ -8702,18 +8742,20 @@ kmem_cache_downsize(void)
nr_cpu_ids = kt->cpus;

ARRAY_LENGTH(kmem_cache_s_array) = nr_cpu_ids;
ASSIGN_SIZE(kmem_cache_s) = OFFSET(kmem_cache_s_array) +
sizeof(ulong) * nr_cpu_ids;

if (!object_size)
ASSIGN_SIZE(kmem_cache_s) = OFFSET(kmem_cache_s_array) +
sizeof(ulong) * nr_cpu_ids;
if (CRASHDEBUG(1))
fprintf(fp, "kmem_cache_downsize: %ld to %ld\n",
fprintf(fp, "\nkmem_cache_downsize: %ld to %ld\n",
STRUCT_SIZE("kmem_cache"), SIZE(kmem_cache_s));
return;
}

cache_buf = GETBUF(SIZE(kmem_cache_s));

if (!readmem(symbol_value("cache_cache"), KVADDR, cache_buf,
SIZE(kmem_cache_s), "kmem_cache buffer", FAULT_ON_ERROR)) {
SIZE(kmem_cache_s), "kmem_cache buffer", RETURN_ON_ERROR)) {
FREEBUF(cache_buf);
return;
}
Expand Down Expand Up @@ -8741,8 +8783,7 @@ kmem_cache_downsize(void)

if (CRASHDEBUG(1)) {
fprintf(fp,
"\nkmem_cache_downsize: SIZE(kmem_cache_s): %ld "
"cache_cache.buffer_size: %d\n",
"\nkmem_cache_downsize: %ld to %d\n",
STRUCT_SIZE("kmem_cache"), buffer_size);
fprintf(fp,
"kmem_cache_downsize: nr_node_ids: %ld\n",
Expand Down Expand Up @@ -16790,6 +16831,8 @@ kmem_cache_init_slub(void)
"kmem_cache_init_slub: numnodes: %d without CONFIG_NUMA\n",
vt->numnodes);

kmem_cache_downsize();

vt->cpu_slab_type = MEMBER_TYPE("kmem_cache", "cpu_slab");

vt->flags |= KMEM_CACHE_INIT;
Expand Down

0 comments on commit c0b7a74

Please sign in to comment.