powerpc/pseries: Fix buffer overflow when reading from pstore

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>
This commit is contained in:
Aruna Balakrishnaiah 2013-08-08 22:33:49 +05:30 committed by Benjamin Herrenschmidt
parent 4e90a2a737
commit 7e76f34fa1
1 changed files with 24 additions and 46 deletions

View File

@ -569,35 +569,6 @@ error:
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 */
@ -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]) {
@ -749,30 +719,36 @@ read_partition:
*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;
@ -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) {
@ -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",