aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-11-11 15:32:44 -0500
committerLen Brown <len.brown@intel.com>2008-12-19 04:40:35 -0500
commit69643279a88dea000ac2f858091d0e365f778245 (patch)
treec6b9a678ccfe9a4e22f747cb05b1bcf789e1b8d0 /kernel/power
parentba84ed9546e91348fdf3ff2bff859b0ee53b407a (diff)
Hibernate: Do not oops on resume if image data are incorrect
During resume from hibernation using the userland interface image data are being passed from the used space process to the kernel. These data need not be valid, but currently the kernel sometimes oopses if it gets invalid image data, which is wrong. Make the kernel return error codes to the user space in such cases. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/snapshot.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 5d2ab836e998..955c8cc91838 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -519,6 +519,14 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
519 return test_bit(bit, addr); 519 return test_bit(bit, addr);
520} 520}
521 521
522static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn)
523{
524 void *addr;
525 unsigned int bit;
526
527 return !memory_bm_find_bit(bm, pfn, &addr, &bit);
528}
529
522/** 530/**
523 * memory_bm_next_pfn - find the pfn that corresponds to the next set bit 531 * memory_bm_next_pfn - find the pfn that corresponds to the next set bit
524 * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is 532 * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is
@@ -1459,9 +1467,7 @@ load_header(struct swsusp_info *info)
1459 * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set 1467 * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set
1460 * the corresponding bit in the memory bitmap @bm 1468 * the corresponding bit in the memory bitmap @bm
1461 */ 1469 */
1462 1470static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
1463static inline void
1464unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
1465{ 1471{
1466 int j; 1472 int j;
1467 1473
@@ -1469,8 +1475,13 @@ unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
1469 if (unlikely(buf[j] == BM_END_OF_MAP)) 1475 if (unlikely(buf[j] == BM_END_OF_MAP))
1470 break; 1476 break;
1471 1477
1472 memory_bm_set_bit(bm, buf[j]); 1478 if (memory_bm_pfn_present(bm, buf[j]))
1479 memory_bm_set_bit(bm, buf[j]);
1480 else
1481 return -EFAULT;
1473 } 1482 }
1483
1484 return 0;
1474} 1485}
1475 1486
1476/* List of "safe" pages that may be used to store data loaded from the suspend 1487/* List of "safe" pages that may be used to store data loaded from the suspend
@@ -1608,7 +1619,7 @@ get_highmem_page_buffer(struct page *page, struct chain_allocator *ca)
1608 pbe = chain_alloc(ca, sizeof(struct highmem_pbe)); 1619 pbe = chain_alloc(ca, sizeof(struct highmem_pbe));
1609 if (!pbe) { 1620 if (!pbe) {
1610 swsusp_free(); 1621 swsusp_free();
1611 return NULL; 1622 return ERR_PTR(-ENOMEM);
1612 } 1623 }
1613 pbe->orig_page = page; 1624 pbe->orig_page = page;
1614 if (safe_highmem_pages > 0) { 1625 if (safe_highmem_pages > 0) {
@@ -1677,7 +1688,7 @@ prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p)
1677static inline void * 1688static inline void *
1678get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) 1689get_highmem_page_buffer(struct page *page, struct chain_allocator *ca)
1679{ 1690{
1680 return NULL; 1691 return ERR_PTR(-EINVAL);
1681} 1692}
1682 1693
1683static inline void copy_last_highmem_page(void) {} 1694static inline void copy_last_highmem_page(void) {}
@@ -1788,8 +1799,13 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
1788static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) 1799static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
1789{ 1800{
1790 struct pbe *pbe; 1801 struct pbe *pbe;
1791 struct page *page = pfn_to_page(memory_bm_next_pfn(bm)); 1802 struct page *page;
1803 unsigned long pfn = memory_bm_next_pfn(bm);
1792 1804
1805 if (pfn == BM_END_OF_MAP)
1806 return ERR_PTR(-EFAULT);
1807
1808 page = pfn_to_page(pfn);
1793 if (PageHighMem(page)) 1809 if (PageHighMem(page))
1794 return get_highmem_page_buffer(page, ca); 1810 return get_highmem_page_buffer(page, ca);
1795 1811
@@ -1805,7 +1821,7 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
1805 pbe = chain_alloc(ca, sizeof(struct pbe)); 1821 pbe = chain_alloc(ca, sizeof(struct pbe));
1806 if (!pbe) { 1822 if (!pbe) {
1807 swsusp_free(); 1823 swsusp_free();
1808 return NULL; 1824 return ERR_PTR(-ENOMEM);
1809 } 1825 }
1810 pbe->orig_address = page_address(page); 1826 pbe->orig_address = page_address(page);
1811 pbe->address = safe_pages_list; 1827 pbe->address = safe_pages_list;
@@ -1868,7 +1884,10 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count)
1868 return error; 1884 return error;
1869 1885
1870 } else if (handle->prev <= nr_meta_pages) { 1886 } else if (handle->prev <= nr_meta_pages) {
1871 unpack_orig_pfns(buffer, &copy_bm); 1887 error = unpack_orig_pfns(buffer, &copy_bm);
1888 if (error)
1889 return error;
1890
1872 if (handle->prev == nr_meta_pages) { 1891 if (handle->prev == nr_meta_pages) {
1873 error = prepare_image(&orig_bm, &copy_bm); 1892 error = prepare_image(&orig_bm, &copy_bm);
1874 if (error) 1893 if (error)
@@ -1879,12 +1898,14 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count)
1879 restore_pblist = NULL; 1898 restore_pblist = NULL;
1880 handle->buffer = get_buffer(&orig_bm, &ca); 1899 handle->buffer = get_buffer(&orig_bm, &ca);
1881 handle->sync_read = 0; 1900 handle->sync_read = 0;
1882 if (!handle->buffer) 1901 if (IS_ERR(handle->buffer))
1883 return -ENOMEM; 1902 return PTR_ERR(handle->buffer);
1884 } 1903 }
1885 } else { 1904 } else {
1886 copy_last_highmem_page(); 1905 copy_last_highmem_page();
1887 handle->buffer = get_buffer(&orig_bm, &ca); 1906 handle->buffer = get_buffer(&orig_bm, &ca);
1907 if (IS_ERR(handle->buffer))
1908 return PTR_ERR(handle->buffer);
1888 if (handle->buffer != buffer) 1909 if (handle->buffer != buffer)
1889 handle->sync_read = 0; 1910 handle->sync_read = 0;
1890 } 1911 }