mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-18 08:56:23 +07:00
Fixes /dev/mem to read back zeros for System RAM areas in the 1MB exception
area on x86 to avoid exposing RAM or tripping hardened usercopy. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 Comment: Kees Cook <kees@outflux.net> iQIcBAABCgAGBQJY7ncoAAoJEIly9N/cbcAm6o0QAJKhA+/CnTRr/knMv0ZE7EW0 AuP/Hxdxfu/OCIc+BMDApdfme4yGWLjiD2Jx6GNDy9o1FaKCdJ3MaCOlPNlNa/5o V+n6z2d7CNDpaiNelhUs38JZGK2aSTYC9a0xQ9JEsQnaunwfHUiirZkdL+ajJI4p 4XOlajWq/mvnBetv8EyZRmBSy51HghNQmk+I0OtyerufZCwwOsbKeDcYr2lqxe7R WtBtvKJF1p55nsNMXG8L62+q4gY5NGtspwQ/7MLrYwmHI9eOdRLzXZdrqH52PvuF H1sk6xQ4Xl89Fp43akybaGu6UyTPU09r1Y9LSpgxNApvqdDOsqB+zpD7gq3iWX/c dtORmMOV3JHyATZkDISX8dN/Qx6bXnsfpfempFd/d+YvdOyh8yRw+ZMCy/2Zx1XP EaEzHMn6DuOGaROhtDGywXylw1CXFzohnfbeCJ2wiQuPWXPDkyFyqmWjwntkP+TD jzx+M6glP0Vq7UHScLcJ6mvu65UnfMdNSo+/t4mS2Xg2xsyG5maQ4GQoxAbpmW26 uSZIrxSFlq0kffeyoG9l5lnbTKI24pDf9O98ZiyBM2fOytdQ2LBtxbHI9I6DPHYS u9QQDsETuWj8LPqcy2stp8BNloTIUdbWwIcuCT/MME/s5qpdkRMEwmLQlXVz64zk BcmDSmhY7ohAaD8dAnlz =5z+N -----END PGP SIGNATURE----- Merge tag 'devmem-v4.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull CONFIG_STRICT_DEVMEM fix from Kees Cook: "Fixes /dev/mem to read back zeros for System RAM areas in the 1MB exception area on x86 to avoid exposing RAM or tripping hardened usercopy" * tag 'devmem-v4.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: mm: Tighten x86 /dev/mem with zeroing reads
This commit is contained in:
commit
1882e562d3
@ -643,21 +643,40 @@ void __init init_mem_mapping(void)
|
||||
* devmem_is_allowed() checks to see if /dev/mem access to a certain address
|
||||
* is valid. The argument is a physical page number.
|
||||
*
|
||||
*
|
||||
* On x86, access has to be given to the first megabyte of ram because that area
|
||||
* contains BIOS code and data regions used by X and dosemu and similar apps.
|
||||
* Access has to be given to non-kernel-ram areas as well, these contain the PCI
|
||||
* mmio resources as well as potential bios/acpi data regions.
|
||||
* On x86, access has to be given to the first megabyte of RAM because that
|
||||
* area traditionally contains BIOS code and data regions used by X, dosemu,
|
||||
* and similar apps. Since they map the entire memory range, the whole range
|
||||
* must be allowed (for mapping), but any areas that would otherwise be
|
||||
* disallowed are flagged as being "zero filled" instead of rejected.
|
||||
* Access has to be given to non-kernel-ram areas as well, these contain the
|
||||
* PCI mmio resources as well as potential bios/acpi data regions.
|
||||
*/
|
||||
int devmem_is_allowed(unsigned long pagenr)
|
||||
{
|
||||
if (pagenr < 256)
|
||||
return 1;
|
||||
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
|
||||
if (page_is_ram(pagenr)) {
|
||||
/*
|
||||
* For disallowed memory regions in the low 1MB range,
|
||||
* request that the page be shown as all zeros.
|
||||
*/
|
||||
if (pagenr < 256)
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
if (!page_is_ram(pagenr))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This must follow RAM test, since System RAM is considered a
|
||||
* restricted resource under CONFIG_STRICT_IOMEM.
|
||||
*/
|
||||
if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
|
||||
/* Low 1MB bypasses iomem restrictions. */
|
||||
if (pagenr < 256)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void free_init_pages(char *what, unsigned long begin, unsigned long end)
|
||||
|
@ -60,6 +60,10 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STRICT_DEVMEM
|
||||
static inline int page_is_allowed(unsigned long pfn)
|
||||
{
|
||||
return devmem_is_allowed(pfn);
|
||||
}
|
||||
static inline int range_is_allowed(unsigned long pfn, unsigned long size)
|
||||
{
|
||||
u64 from = ((u64)pfn) << PAGE_SHIFT;
|
||||
@ -75,6 +79,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static inline int page_is_allowed(unsigned long pfn)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static inline int range_is_allowed(unsigned long pfn, unsigned long size)
|
||||
{
|
||||
return 1;
|
||||
@ -122,23 +130,31 @@ static ssize_t read_mem(struct file *file, char __user *buf,
|
||||
|
||||
while (count > 0) {
|
||||
unsigned long remaining;
|
||||
int allowed;
|
||||
|
||||
sz = size_inside_page(p, count);
|
||||
|
||||
if (!range_is_allowed(p >> PAGE_SHIFT, count))
|
||||
allowed = page_is_allowed(p >> PAGE_SHIFT);
|
||||
if (!allowed)
|
||||
return -EPERM;
|
||||
if (allowed == 2) {
|
||||
/* Show zeros for restricted memory. */
|
||||
remaining = clear_user(buf, sz);
|
||||
} else {
|
||||
/*
|
||||
* On ia64 if a page has been mapped somewhere as
|
||||
* uncached, then it must also be accessed uncached
|
||||
* by the kernel or data corruption may occur.
|
||||
*/
|
||||
ptr = xlate_dev_mem_ptr(p);
|
||||
if (!ptr)
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* On ia64 if a page has been mapped somewhere as uncached, then
|
||||
* it must also be accessed uncached by the kernel or data
|
||||
* corruption may occur.
|
||||
*/
|
||||
ptr = xlate_dev_mem_ptr(p);
|
||||
if (!ptr)
|
||||
return -EFAULT;
|
||||
remaining = copy_to_user(buf, ptr, sz);
|
||||
|
||||
unxlate_dev_mem_ptr(p, ptr);
|
||||
}
|
||||
|
||||
remaining = copy_to_user(buf, ptr, sz);
|
||||
unxlate_dev_mem_ptr(p, ptr);
|
||||
if (remaining)
|
||||
return -EFAULT;
|
||||
|
||||
@ -181,30 +197,36 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
|
||||
#endif
|
||||
|
||||
while (count > 0) {
|
||||
int allowed;
|
||||
|
||||
sz = size_inside_page(p, count);
|
||||
|
||||
if (!range_is_allowed(p >> PAGE_SHIFT, sz))
|
||||
allowed = page_is_allowed(p >> PAGE_SHIFT);
|
||||
if (!allowed)
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* On ia64 if a page has been mapped somewhere as uncached, then
|
||||
* it must also be accessed uncached by the kernel or data
|
||||
* corruption may occur.
|
||||
*/
|
||||
ptr = xlate_dev_mem_ptr(p);
|
||||
if (!ptr) {
|
||||
if (written)
|
||||
break;
|
||||
return -EFAULT;
|
||||
}
|
||||
/* Skip actual writing when a page is marked as restricted. */
|
||||
if (allowed == 1) {
|
||||
/*
|
||||
* On ia64 if a page has been mapped somewhere as
|
||||
* uncached, then it must also be accessed uncached
|
||||
* by the kernel or data corruption may occur.
|
||||
*/
|
||||
ptr = xlate_dev_mem_ptr(p);
|
||||
if (!ptr) {
|
||||
if (written)
|
||||
break;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
copied = copy_from_user(ptr, buf, sz);
|
||||
unxlate_dev_mem_ptr(p, ptr);
|
||||
if (copied) {
|
||||
written += sz - copied;
|
||||
if (written)
|
||||
break;
|
||||
return -EFAULT;
|
||||
copied = copy_from_user(ptr, buf, sz);
|
||||
unxlate_dev_mem_ptr(p, ptr);
|
||||
if (copied) {
|
||||
written += sz - copied;
|
||||
if (written)
|
||||
break;
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
buf += sz;
|
||||
|
Loading…
Reference in New Issue
Block a user