Commit 7e76f34f authored by Aruna Balakrishnaiah's avatar Aruna Balakrishnaiah Committed by Benjamin Herrenschmidt

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: default avatarAruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 4e90a2a7
...@@ -569,35 +569,6 @@ int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen) ...@@ -569,35 +569,6 @@ int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
return ret; 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) static int nvram_pstore_open(struct pstore_info *psi)
{ {
/* Reset the iterator to start reading partitions again */ /* 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, ...@@ -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; unsigned int err_type, id_no, size = 0;
struct nvram_os_partition *part = NULL; struct nvram_os_partition *part = NULL;
char *buff = NULL, *big_buff = NULL; char *buff = NULL, *big_buff = NULL;
int rc, sig = 0; int sig = 0;
loff_t p; loff_t p;
read_partition:
read_type++; read_type++;
switch (nvram_type_ids[read_type]) { switch (nvram_type_ids[read_type]) {
...@@ -749,30 +719,36 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, ...@@ -749,30 +719,36 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
*id = id_no; *id = id_no;
if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
int length, unzipped_len;
oops_hdr = (struct oops_log_info *)buff; 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) { if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL); big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (!big_buff) if (!big_buff)
return -ENOMEM; return -ENOMEM;
rc = unzip_oops(buff, big_buff); unzipped_len = nvram_decompress(*buf, big_buff,
length, big_oops_buf_sz);
if (rc != 0) { if (unzipped_len < 0) {
kfree(buff); pr_err("nvram: decompression failed, returned "
"rc %d\n", unzipped_len);
kfree(big_buff); 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);
} }
return length;
time->tv_sec = oops_hdr->timestamp;
time->tv_nsec = 0;
return oops_hdr->report_length;
} }
*buf = buff; *buf = buff;
...@@ -816,6 +792,7 @@ static int nvram_pstore_init(void) ...@@ -816,6 +792,7 @@ static int nvram_pstore_init(void)
static void __init nvram_init_oops_partition(int rtas_partition_exists) static void __init nvram_init_oops_partition(int rtas_partition_exists)
{ {
int rc; int rc;
size_t size;
rc = pseries_nvram_init_os_partition(&oops_log_partition); rc = pseries_nvram_init_os_partition(&oops_log_partition);
if (rc != 0) { if (rc != 0) {
...@@ -844,8 +821,9 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) ...@@ -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_sz = (oops_data_sz * 100) / 45;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (big_oops_buf) { if (big_oops_buf) {
stream.workspace = kmalloc(zlib_deflate_workspacesize( size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
WINDOW_BITS, MEM_LEVEL), GFP_KERNEL); zlib_inflate_workspacesize());
stream.workspace = kmalloc(size, GFP_KERNEL);
if (!stream.workspace) { if (!stream.workspace) {
pr_err("nvram: No memory for compression workspace; " pr_err("nvram: No memory for compression workspace; "
"skipping compression of %s partition data\n", "skipping compression of %s partition data\n",
......
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