From 3fbd61fbbbfa7ae15cd3f3e2ff7a97e106be2b43 Mon Sep 17 00:00:00 2001 From: Dave Anderson Date: Tue, 26 Nov 2013 12:42:46 -0500 Subject: [PATCH] crash-driver Bugzilla: N/A Upstream-status: Fedora mustard --- arch/arm/include/asm/crash-driver.h | 6 ++ arch/arm64/include/asm/crash-driver.h | 6 ++ arch/ia64/include/asm/crash-driver.h | 90 ++++++++++++++++++++++ arch/ia64/kernel/ia64_ksyms.c | 3 + arch/powerpc/include/asm/crash-driver.h | 6 ++ arch/s390/include/asm/crash-driver.h | 60 +++++++++++++++ arch/s390/mm/maccess.c | 2 + arch/x86/include/asm/crash-driver.h | 6 ++ drivers/char/Kconfig | 3 + drivers/char/Makefile | 2 + drivers/char/crash.c | 128 ++++++++++++++++++++++++++++++++ include/asm-generic/crash-driver.h | 72 ++++++++++++++++++ 12 files changed, 384 insertions(+) create mode 100644 arch/arm/include/asm/crash-driver.h create mode 100644 arch/arm64/include/asm/crash-driver.h create mode 100644 arch/ia64/include/asm/crash-driver.h create mode 100644 arch/powerpc/include/asm/crash-driver.h create mode 100644 arch/s390/include/asm/crash-driver.h create mode 100644 arch/x86/include/asm/crash-driver.h create mode 100644 drivers/char/crash.c create mode 100644 include/asm-generic/crash-driver.h diff --git a/arch/arm/include/asm/crash-driver.h b/arch/arm/include/asm/crash-driver.h new file mode 100644 index 0000000..06e7ae9 --- /dev/null +++ b/arch/arm/include/asm/crash-driver.h @@ -0,0 +1,6 @@ +#ifndef _ARM_CRASH_H +#define _ARM_CRASH_H + +#include + +#endif /* _ARM_CRASH_H */ diff --git a/arch/arm64/include/asm/crash-driver.h b/arch/arm64/include/asm/crash-driver.h new file mode 100644 index 0000000..43b26da --- /dev/null +++ b/arch/arm64/include/asm/crash-driver.h @@ -0,0 +1,6 @@ +#ifndef _ARM64_CRASH_H +#define _ARM64_CRASH_H + +#include + +#endif /* _ARM64_CRASH_H */ diff --git a/arch/ia64/include/asm/crash-driver.h b/arch/ia64/include/asm/crash-driver.h new file mode 100644 index 0000000..404bcb9 --- /dev/null +++ b/arch/ia64/include/asm/crash-driver.h @@ -0,0 +1,90 @@ +#ifndef _ASM_IA64_CRASH_H +#define _ASM_IA64_CRASH_H + +/* + * linux/include/asm-ia64/crash-driver.h + * + * Copyright (c) 2004 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __KERNEL__ + +#include +#include +#include + +static inline void * +map_virtual(u64 offset, struct page **pp) +{ + struct page *page; + unsigned long pfn; + u32 type; + + if (REGION_NUMBER(offset) == 5) { + char byte; + + if (__get_user(byte, (char *)offset) == 0) + return (void *)offset; + else + return NULL; + } + + switch (type = efi_mem_type(offset)) + { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + break; + + default: + printk(KERN_INFO + "crash memory driver: invalid memory type for %lx: %d\n", + offset, type); + return NULL; + } + + pfn = offset >> PAGE_SHIFT; + + if (!pfn_valid(pfn)) { + printk(KERN_INFO + "crash memory driver: invalid pfn: %lx )\n", pfn); + return NULL; + } + + page = pfn_to_page(pfn); + + if (!page->virtual) { + printk(KERN_INFO + "crash memory driver: offset: %lx page: %lx page->virtual: NULL\n", + offset, (unsigned long)page); + return NULL; + } + + return (page->virtual + (offset & (PAGE_SIZE-1))); +} + +static inline void unmap_virtual(struct page *page) +{ + return; +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_IA64_CRASH_H */ diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 0967310..e888878 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -84,6 +84,9 @@ EXPORT_SYMBOL(ia64_save_scratch_fpregs); #include EXPORT_SYMBOL(unw_init_running); +#include +EXPORT_SYMBOL_GPL(efi_mem_type); + #if defined(CONFIG_IA64_ESI) || defined(CONFIG_IA64_ESI_MODULE) extern void esi_call_phys (void); EXPORT_SYMBOL_GPL(esi_call_phys); diff --git a/arch/powerpc/include/asm/crash-driver.h b/arch/powerpc/include/asm/crash-driver.h new file mode 100644 index 0000000..50092d9 --- /dev/null +++ b/arch/powerpc/include/asm/crash-driver.h @@ -0,0 +1,6 @@ +#ifndef _PPC64_CRASH_H +#define _PPC64_CRASH_H + +#include + +#endif /* _PPC64_CRASH_H */ diff --git a/arch/s390/include/asm/crash-driver.h b/arch/s390/include/asm/crash-driver.h new file mode 100644 index 0000000..552be5e --- /dev/null +++ b/arch/s390/include/asm/crash-driver.h @@ -0,0 +1,60 @@ +#ifndef _S390_CRASH_H +#define _S390_CRASH_H + +#ifdef __KERNEL__ + +#include +#include + +/* + * For swapped prefix pages get bounce buffer using xlate_dev_mem_ptr() + */ +static inline void *map_virtual(u64 offset, struct page **pp) +{ + struct page *page; + unsigned long pfn; + void *vaddr; + + vaddr = xlate_dev_mem_ptr(offset); + pfn = ((unsigned long) vaddr) >> PAGE_SHIFT; + if ((unsigned long) vaddr != offset) + page = pfn_to_page(pfn); + else + page = NULL; + + if (!page_is_ram(pfn)) { + printk(KERN_INFO + "crash memory driver: !page_is_ram(pfn: %lx)\n", pfn); + return NULL; + } + + if (!pfn_valid(pfn)) { + printk(KERN_INFO + "crash memory driver: invalid pfn: %lx )\n", pfn); + return NULL; + } + + *pp = page; + return vaddr; +} + +/* + * Free bounce buffer if necessary + */ +static inline void unmap_virtual(struct page *page) +{ + void *vaddr; + + if (page) { + /* + * Because for bounce buffers vaddr will never be 0 + * unxlate_dev_mem_ptr() will always free the bounce buffer. + */ + vaddr = (void *)(page_to_pfn(page) << PAGE_SHIFT); + unxlate_dev_mem_ptr(0, vaddr); + } +} + +#endif /* __KERNEL__ */ + +#endif /* _S390_CRASH_H */ diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 792f9c6..3197995 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c @@ -201,6 +201,7 @@ void *xlate_dev_mem_ptr(phys_addr_t addr) put_online_cpus(); return bounce; } +EXPORT_SYMBOL_GPL(xlate_dev_mem_ptr); /* * Free converted buffer for /dev/mem access (if necessary) @@ -210,3 +211,4 @@ void unxlate_dev_mem_ptr(phys_addr_t addr, void *buf) if ((void *) addr != buf) free_page((unsigned long) buf); } +EXPORT_SYMBOL_GPL(unxlate_dev_mem_ptr); diff --git a/arch/x86/include/asm/crash-driver.h b/arch/x86/include/asm/crash-driver.h new file mode 100644 index 0000000..fd4736e --- /dev/null +++ b/arch/x86/include/asm/crash-driver.h @@ -0,0 +1,6 @@ +#ifndef _X86_CRASH_H +#define _X86_CRASH_H + +#include + +#endif /* _X86_CRASH_H */ diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fdb8f3e..7dd3a49 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -4,6 +4,9 @@ menu "Character devices" +config CRASH + tristate "Crash Utility memory driver" + source "drivers/tty/Kconfig" config DEVMEM diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 55d16bf..a40ace9 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -61,3 +61,5 @@ js-rtc-y = rtc.o obj-$(CONFIG_TILE_SROM) += tile-srom.o obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o + +obj-$(CONFIG_CRASH) += crash.o diff --git a/drivers/char/crash.c b/drivers/char/crash.c new file mode 100644 index 0000000..085378a --- /dev/null +++ b/drivers/char/crash.c @@ -0,0 +1,128 @@ +/* + * linux/drivers/char/crash.c + * + * Copyright (C) 2004 Dave Anderson + * Copyright (C) 2004 Red Hat, Inc. + */ + +/****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CRASH_VERSION "1.0" + +/* + * These are the file operation functions that allow crash utility + * access to physical memory. + */ + +static loff_t +crash_llseek(struct file * file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } +} + +/* + * Determine the page address for an address offset value, + * get a virtual address for it, and copy it out. + * Accesses must fit within a page. + */ +static ssize_t +crash_read(struct file *file, char *buf, size_t count, loff_t *poff) +{ + void *vaddr; + struct page *page; + u64 offset; + ssize_t read; + + offset = *poff; + if (offset >> PAGE_SHIFT != (offset+count-1) >> PAGE_SHIFT) + return -EINVAL; + + vaddr = map_virtual(offset, &page); + if (!vaddr) + return -EFAULT; + + if (copy_to_user(buf, vaddr, count)) { + unmap_virtual(page); + return -EFAULT; + } + unmap_virtual(page); + + read = count; + *poff += read; + return read; +} + +static struct file_operations crash_fops = { + .owner = THIS_MODULE, + .llseek = crash_llseek, + .read = crash_read, +}; + +static struct miscdevice crash_dev = { + MISC_DYNAMIC_MINOR, + "crash", + &crash_fops +}; + +static int __init +crash_init(void) +{ + int ret; + + ret = misc_register(&crash_dev); + if (ret) { + printk(KERN_ERR + "crash memory driver: cannot misc_register (MISC_DYNAMIC_MINOR)\n"); + goto out; + } + + ret = 0; + printk(KERN_INFO "crash memory driver: version %s\n", CRASH_VERSION); +out: + return ret; +} + +static void __exit +crash_cleanup_module(void) +{ + misc_deregister(&crash_dev); +} + +module_init(crash_init); +module_exit(crash_cleanup_module); + +MODULE_LICENSE("GPL"); diff --git a/include/asm-generic/crash-driver.h b/include/asm-generic/crash-driver.h new file mode 100644 index 0000000..25ab986 --- /dev/null +++ b/include/asm-generic/crash-driver.h @@ -0,0 +1,72 @@ +#ifndef __CRASH_H__ +#define __CRASH_H__ + +/* + * include/linux/crash-driver.h + * + * Copyright (c) 2013 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __KERNEL__ + +#include +#include + +static inline void * +map_virtual(u64 offset, struct page **pp) +{ + struct page *page; + unsigned long pfn; + void *vaddr; + + pfn = (unsigned long)(offset >> PAGE_SHIFT); + + if (!page_is_ram(pfn)) { + printk(KERN_INFO + "crash memory driver: !page_is_ram(pfn: %lx)\n", pfn); + return NULL; + } + + if (!pfn_valid(pfn)) { + printk(KERN_INFO + "crash memory driver: invalid pfn: %lx )\n", pfn); + return NULL; + } + + page = pfn_to_page(pfn); + + vaddr = kmap(page); + if (!vaddr) { + printk(KERN_INFO + "crash memory driver: pfn: %lx kmap(page: %lx) failed\n", + pfn, (unsigned long)page); + return NULL; + } + + *pp = page; + return (vaddr + (offset & (PAGE_SIZE-1))); +} + +static inline void unmap_virtual(struct page *page) +{ + kunmap(page); +} + +#endif /* __KERNEL__ */ + +#endif /* __CRASH_H__ */ -- 2.9.2 From 7523c19e1d22fbabeaeae9520c16a78202c0eefe Mon Sep 17 00:00:00 2001 From: Fedora Kernel Team Date: Tue, 20 Sep 2016 19:39:46 +0200 Subject: [PATCH] Update of crash driver to handle CONFIG_HARDENED_USERCOPY and to restrict the supported architectures. --- drivers/char/Kconfig | 1 + drivers/char/crash.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 99b99d5..be6a3ae 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,6 +6,7 @@ menu "Character devices" config CRASH tristate "Crash Utility memory driver" + depends on X86_32 || X86_64 || ARM || ARM64 || PPC64 || S390 source "drivers/tty/Kconfig" diff --git a/drivers/char/crash.c b/drivers/char/crash.c index 085378a..0258bf8 100644 --- a/drivers/char/crash.c +++ b/drivers/char/crash.c @@ -32,7 +32,7 @@ #include #include -#define CRASH_VERSION "1.0" +#define CRASH_VERSION "1.2" /* * These are the file operation functions that allow crash utility @@ -66,6 +66,7 @@ crash_read(struct file *file, char *buf, size_t count, loff_t *poff) struct page *page; u64 offset; ssize_t read; + char *buffer = file->private_data; offset = *poff; if (offset >> PAGE_SHIFT != (offset+count-1) >> PAGE_SHIFT) @@ -74,8 +75,12 @@ crash_read(struct file *file, char *buf, size_t count, loff_t *poff) vaddr = map_virtual(offset, &page); if (!vaddr) return -EFAULT; - - if (copy_to_user(buf, vaddr, count)) { + /* + * Use bounce buffer to bypass the CONFIG_HARDENED_USERCOPY + * kernel text restriction. + */ + memcpy(buffer, (char *)vaddr, count); + if (copy_to_user(buf, buffer, count)) { unmap_virtual(page); return -EFAULT; } @@ -86,10 +91,32 @@ crash_read(struct file *file, char *buf, size_t count, loff_t *poff) return read; } +static int +crash_open(struct inode * inode, struct file * filp) +{ + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + filp->private_data = (void *)__get_free_page(GFP_KERNEL); + if (!filp->private_data) + return -ENOMEM; + + return 0; +} + +static int +crash_release(struct inode *inode, struct file *filp) +{ + free_pages((unsigned long)filp->private_data, 0); + return 0; +} + static struct file_operations crash_fops = { .owner = THIS_MODULE, .llseek = crash_llseek, .read = crash_read, + .open = crash_open, + .release = crash_release, }; static struct miscdevice crash_dev = { -- 2.9.3