Skip to content

Commit

Permalink
powerpc/pseries: Fix buffer overflow when reading from pstore
Browse files Browse the repository at this point in the history
When reading from pstore there is a buffer overflow during decompression
due to the header added in unzip_oops. Remove unzip_oops and call
pstore_decompress directly in nvram_pstore_read. Allocate buffer of size
report_length of the oops header as header will not be deallocated in pstore.
Since we have 'openssl' command line tool to decompress the compressed data,
dump the compressed data in case decompression fails instead of not dumping
anything.

Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Aruna Balakrishnaiah authored and Benjamin Herrenschmidt committed Aug 9, 2013
1 parent 4e90a2a commit 7e76f34
Showing 1 changed file with 24 additions and 46 deletions.
70 changes: 24 additions & 46 deletions arch/powerpc/platforms/pseries/nvram.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,35 +569,6 @@ int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
return ret;
}

static int unzip_oops(char *oops_buf, char *big_buf)
{
struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
u64 timestamp = oops_hdr->timestamp;
char *big_oops_data = NULL;
char *oops_data_buf = NULL;
size_t big_oops_data_sz;
int unzipped_len;

big_oops_data = big_buf + sizeof(struct oops_log_info);
big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info);
oops_data_buf = oops_buf + sizeof(struct oops_log_info);

unzipped_len = nvram_decompress(oops_data_buf, big_oops_data,
oops_hdr->report_length,
big_oops_data_sz);

if (unzipped_len < 0) {
pr_err("nvram: decompression failed; returned %d\n",
unzipped_len);
return -1;
}
oops_hdr = (struct oops_log_info *)big_buf;
oops_hdr->version = OOPS_HDR_VERSION;
oops_hdr->report_length = (u16) unzipped_len;
oops_hdr->timestamp = timestamp;
return 0;
}

static int nvram_pstore_open(struct pstore_info *psi)
{
/* Reset the iterator to start reading partitions again */
Expand Down Expand Up @@ -685,10 +656,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
unsigned int err_type, id_no, size = 0;
struct nvram_os_partition *part = NULL;
char *buff = NULL, *big_buff = NULL;
int rc, sig = 0;
int sig = 0;
loff_t p;

read_partition:
read_type++;

switch (nvram_type_ids[read_type]) {
Expand Down Expand Up @@ -749,30 +719,36 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
*id = id_no;

if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
int length, unzipped_len;

oops_hdr = (struct oops_log_info *)buff;
*buf = buff + sizeof(*oops_hdr);
length = oops_hdr->report_length;
*buf = kmalloc(length, GFP_KERNEL);
if (*buf == NULL)
return -ENOMEM;
memcpy(*buf, buff + sizeof(*oops_hdr), length);
time->tv_sec = oops_hdr->timestamp;
time->tv_nsec = 0;
kfree(buff);

if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (!big_buff)
return -ENOMEM;

rc = unzip_oops(buff, big_buff);
unzipped_len = nvram_decompress(*buf, big_buff,
length, big_oops_buf_sz);

if (rc != 0) {
kfree(buff);
if (unzipped_len < 0) {
pr_err("nvram: decompression failed, returned "
"rc %d\n", unzipped_len);
kfree(big_buff);
goto read_partition;
} else {
*buf = big_buff;
length = unzipped_len;
}

oops_hdr = (struct oops_log_info *)big_buff;
*buf = big_buff + sizeof(*oops_hdr);
kfree(buff);
}

time->tv_sec = oops_hdr->timestamp;
time->tv_nsec = 0;
return oops_hdr->report_length;
return length;
}

*buf = buff;
Expand Down Expand Up @@ -816,6 +792,7 @@ static int nvram_pstore_init(void)
static void __init nvram_init_oops_partition(int rtas_partition_exists)
{
int rc;
size_t size;

rc = pseries_nvram_init_os_partition(&oops_log_partition);
if (rc != 0) {
Expand Down Expand Up @@ -844,8 +821,9 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
big_oops_buf_sz = (oops_data_sz * 100) / 45;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (big_oops_buf) {
stream.workspace = kmalloc(zlib_deflate_workspacesize(
WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
zlib_inflate_workspacesize());
stream.workspace = kmalloc(size, GFP_KERNEL);
if (!stream.workspace) {
pr_err("nvram: No memory for compression workspace; "
"skipping compression of %s partition data\n",
Expand Down

0 comments on commit 7e76f34

Please sign in to comment.