This is a series of patches to support CONFIG_RODATA on ARM, so that
the kernel text is RO, and non-text sections default to NX. To support
on-the-fly kernel text patching (via ftrace, kprobes, etc), fixmap
support has been finalized based on several versions of various patches
that are floating around on the mailing list. This series attempts to
include the least intrusive version, so that others can build on it for
future fixmap work.
The series has been heavily tested, and appears to be working correctly:
With CONFIG_ARM_PTDUMP, expected page table permissions are seen in
/sys/kernel/debug/kernel_page_tables.
Using CONFIG_LKDTM, the kernel now correctly detects bad accesses for
for the following lkdtm tests via /sys/kernel/debug/provoke-crash/DIRECT:
EXEC_DATA
WRITE_RO
WRITE_KERN
ftrace works:
CONFIG_FTRACE_STARTUP_TEST passes
Enabling tracing works:
echo function > /sys/kernel/debug/tracing/current_tracer
kprobes works:
CONFIG_ARM_KPROBES_TEST passes
kexec works:
kexec will load and start a new kernel
Built with and without CONFIG_HIGHMEM, CONFIG_HIGHMEM_DEBUG, and
CONFIG_NR_CPUS=32.
Thanks to everyone who has been testing this series and working on its
various pieces!
Hopefully this should address Will's last concerns. :)
Thanks!
-Kees
v6:
- always run patch_text under stop_machine (will.deacon)
- document set_fixmap's TLB flushing situation (will.deacon)
v5:
- clean up #includes in mmu.c (will.deacon)
- optimize get_cr() test (will.deacon)
- created free_tcmmem to avoid excessive #ifdefs (will.deacon)
- explicitly test irqs_disabled in set_fixmap (will.deacon)
v4:
- expanded fixmap to 3MB to support 32 CPUs (robh)
- corrected pmd-finding via vaddr instead of FIXMAP_START (robh)
- switched structure size test to BUILD_BUG_ON (sboyd)
- added locking annotations to keep sparse happy (sboyd)
- adding missing "static" declarations noticed by sparse
- reorganized fixmap portion of patches
v3:
- more cleanups in switch to generic fixmap (lauraa, robh)
- fixed kexec merge hunk glitch (will.deacon)
- added tested-by tags where appropriate from v2 testing
v2:
- fix typo in kexec merge (buildbot)
- flip index order for highmem pte access (lauraa)
- added kgdb updates (dianders)
From: Rob Herring <robh@kernel.org>
With commit a05e54c103b0 ("ARM: 8031/2: change fixmap mapping region to
support 32 CPUs"), the fixmap region was expanded to 2MB, but it
precluded any other uses of the fixmap region. In order to support other
uses the fixmap region needs to be expanded beyond 2MB. Fortunately, the
adjacent 1MB range 0xffe00000-0xfff00000 is availabe.
Remove fixmap_page_table ptr and lookup the page table via the virtual
address so that the fixmap region can span more that one pmd. The 2nd
pmd is already created since it is shared with the vector page.
Signed-off-by: Rob Herring <robh@kernel.org>
[kees: fixed CONFIG_DEBUG_HIGHMEM get_fixmap() calls]
[kees: moved pte allocation outside of CONFIG_HIGHMEM]
Signed-off-by: Kees Cook <redacted>
Acked-by: Nicolas Pitre <redacted>
---
Documentation/arm/memory.txt | 2 +-
arch/arm/include/asm/fixmap.h | 2 +-
arch/arm/mm/highmem.c | 15 ++++++++-------
arch/arm/mm/mmu.c | 6 +++---
4 files changed, 13 insertions(+), 12 deletions(-)
@@ -41,7 +41,7 @@ fffe8000 fffeffff DTCM mapping area for platforms with fffe0000 fffe7fff ITCM mapping area for platforms with ITCM mounted inside the CPU.-ffc00000 ffdfffff Fixmap mapping region. Addresses provided+ffc00000 ffefffff Fixmap mapping region. Addresses provided by fix_to_virt() will be located here. fee00000 feffffff Mapping of PCI I/O space. This is a static
From: Doug Anderson <dianders@chromium.org>
Handle the case where someone has set the text segment of the kernel
as read-only by using the newly introduced "patch" mechanism.
Signed-off-by: Doug Anderson <dianders@chromium.org>
[kees: switched structure size check to BUILD_BUG_ON (sboyd)]
Signed-off-by: Kees Cook <redacted>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/kernel/Makefile | 2 +-
arch/arm/kernel/kgdb.c | 29 +++++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
From: Mark Salter <redacted>
ARM is different from other architectures in that fixmap pages are indexed
with a positive offset from FIXADDR_START. Other architectures index with
a negative offset from FIXADDR_TOP. In order to use the generic fixmap.h
definitions, this patch redefines FIXADDR_TOP to be inclusive of the
useable range. That is, FIXADDR_TOP is the virtual address of the topmost
fixed page. The newly defined FIXADDR_END is the first virtual address
past the fixed mappings.
Signed-off-by: Mark Salter <redacted>
Reviewed-by: Doug Anderson <dianders@chromium.org>
[kees: update for a05e54c103b0 ("ARM: 8031/2: change fixmap ...")]
Signed-off-by: Kees Cook <redacted>
Cc: Laura Abbott <redacted>
Cc: Rob Herring <robh@kernel.org>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/include/asm/fixmap.h | 27 +++++++++------------------
arch/arm/mm/init.c | 2 +-
2 files changed, 10 insertions(+), 19 deletions(-)
From: Rabin Vincent <redacted>
Use fixmaps for text patching when the kernel text is read-only,
inspired by x86. This makes jump labels and kprobes work with the
currently available CONFIG_DEBUG_SET_MODULE_RONX and the upcoming
CONFIG_DEBUG_RODATA options.
Signed-off-by: Rabin Vincent <redacted>
[kees: fixed up for merge with "arm: use generic fixmap.h"]
[kees: added parse acquire/release annotations to pass C=1 builds]
[kees: always use stop_machine to keep TLB flushing local]
Signed-off-by: Kees Cook <redacted>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/include/asm/fixmap.h | 4 ++
arch/arm/kernel/jump_label.c | 2 +-
arch/arm/kernel/patch.c | 92 ++++++++++++++++++++++++++++++++++---------
arch/arm/kernel/patch.h | 12 +++++-
4 files changed, 89 insertions(+), 21 deletions(-)
@@ -11,6 +11,10 @@ enum fixed_addresses {FIX_KMAP_BEGIN,FIX_KMAP_END=FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,+/* Support writing RO kernel text via kprobes, jump labels, etc. */+FIX_TEXT_POKE0,+FIX_TEXT_POKE1,+__end_of_fixed_addresses};
This is used from set_fixmap() and clear_fixmap() via asm-generic/fixmap.h.
Also makes sure that the fixmap allocation fits into the expected range.
Based on patch by Rabin Vincent.
Signed-off-by: Kees Cook <redacted>
Cc: Rabin Vincent <redacted>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/include/asm/fixmap.h | 2 ++
arch/arm/mm/mmu.c | 24 ++++++++++++++++++++++++
2 files changed, 26 insertions(+)
@@ -393,6 +394,29 @@ SET_MEMORY_FN(x, pte_set_x)SET_MEMORY_FN(nx,pte_set_nx)/*+*ToavoidTLBflushbroadcasts,thisuseslocal_flush_tlb_kernel_range().+*Asaresult,thiscanonlybecalledwithpreemptiondisabled,asunder+*stop_machine().+*/+void__set_fixmap(enumfixed_addressesidx,phys_addr_tphys,pgprot_tprot)+{+unsignedlongvaddr=__fix_to_virt(idx);+pte_t*pte=pte_offset_kernel(pmd_off_k(vaddr),vaddr);++/* Make sure fixmap region does not exceed available allocation. */+BUILD_BUG_ON(FIXADDR_START+(__end_of_fixed_addresses*PAGE_SIZE)>+FIXADDR_END);+BUG_ON(idx>=__end_of_fixed_addresses);++if(pgprot_val(prot))+set_pte_at(NULL,vaddr,pte,+pfn_pte(phys>>PAGE_SHIFT,prot));+else+pte_clear(NULL,vaddr,pte);+local_flush_tlb_kernel_range(vaddr,vaddr+PAGE_SIZE);+}++/**AdjustthePMDsectionentriesaccordingtotheCPUinuse.*/staticvoid__initbuild_mem_type_table(void)
From: Nikolay Borisov <redacted>
With the introduction of Kees Cook's patch to make the kernel .text
read-only the existing method by which kexec works got broken since it
directly pokes some values in the template code, which resides in the
.text section.
The current patch changes the way those values are inserted so that poking
.text section occurs only in machine_kexec (e.g when we are about to nuke
the old kernel and are beyond the point of return). This allows to use
set_kernel_text_rw() to directly patch the values in the .text section.
I had already sent a patch which achieved this but it was significantly
more complicated, so this is a cleaner/straight-forward approach.
Signed-off-by: Nikolay Borisov <redacted>
Acked-by: Will Deacon <redacted>
[kees: collapsed kexec_boot_atags (will.daecon)]
[kees: for bisectability, moved set_kernel_text_rw() to RODATA patch]
Signed-off-by: Kees Cook <redacted>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/kernel/machine_kexec.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
Adds CONFIG_ARM_KERNMEM_PERMS to separate the kernel memory regions
into section-sized areas that can have different permisions. Performs
the NX permission changes during free_initmem, so that init memory can be
reclaimed.
This uses section size instead of PMD size to reduce memory lost to
padding on non-LPAE systems.
Based on work by Brad Spengler, Larry Bassel, and Laura Abbott.
Signed-off-by: Kees Cook <redacted>
Tested-by: Laura Abbott <redacted>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/kernel/vmlinux.lds.S | 17 +++++++
arch/arm/mm/Kconfig | 9 ++++
arch/arm/mm/init.c | 101 +++++++++++++++++++++++++++++++++++++++++-
arch/arm/mm/mmu.c | 13 +++++-
4 files changed, 138 insertions(+), 2 deletions(-)
I'm looking at this, and wondering two things. Firstly, why isn't it
MT_MEMORY_RW in the first place. Secondly, why do you need to make
this depend on CONFIG_ARM_KERNMEM_PERMS at all?
I think the first is an oversight by me (and is a case which never came
up in my testing, because most of my platforms don't have segmented
memory layouts.)
The second I think is not necessary - the memory region being considered
is not part of the kernel at all, and so should not be executable in any
shape or form.
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
I'm looking at this, and wondering two things. Firstly, why isn't it
MT_MEMORY_RW in the first place. Secondly, why do you need to make
this depend on CONFIG_ARM_KERNMEM_PERMS at all?
I think the first is an oversight by me (and is a case which never came
up in my testing, because most of my platforms don't have segmented
memory layouts.)
The second I think is not necessary - the memory region being considered
is not part of the kernel at all, and so should not be executable in any
shape or form.
I'm happy to change this. My original intent was to make layout for
builds without CONFIG_ARM_KERNMEM_PERMS identical to what was there
before, so I took this step to make sure.
I will drop the #ifdef and respin. Does the rest look ok? Shall I send
a pull request?
Thanks!
-Kees
--
Kees Cook
Chrome OS Security
I'm looking at this, and wondering two things. Firstly, why isn't it
MT_MEMORY_RW in the first place. Secondly, why do you need to make
this depend on CONFIG_ARM_KERNMEM_PERMS at all?
I think the first is an oversight by me (and is a case which never came
up in my testing, because most of my platforms don't have segmented
memory layouts.)
The second I think is not necessary - the memory region being considered
is not part of the kernel at all, and so should not be executable in any
shape or form.
I'm happy to change this. My original intent was to make layout for
builds without CONFIG_ARM_KERNMEM_PERMS identical to what was there
before, so I took this step to make sure.
I will drop the #ifdef and respin. Does the rest look ok? Shall I send
a pull request?
I think all you need to is change that MT_MEMORY_RWX to be MT_MEMORY_RW.
However, I think I would also like to see the kernel text being read-only
as soon as possible - so maybe we should also have MT_MEMORY_RX, and
have map_lowmem() use this for the kernel text when we want this level
of protection?
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
I'm looking at this, and wondering two things. Firstly, why isn't it
MT_MEMORY_RW in the first place. Secondly, why do you need to make
this depend on CONFIG_ARM_KERNMEM_PERMS at all?
I think the first is an oversight by me (and is a case which never came
up in my testing, because most of my platforms don't have segmented
memory layouts.)
The second I think is not necessary - the memory region being considered
is not part of the kernel at all, and so should not be executable in any
shape or form.
I'm happy to change this. My original intent was to make layout for
builds without CONFIG_ARM_KERNMEM_PERMS identical to what was there
before, so I took this step to make sure.
I will drop the #ifdef and respin. Does the rest look ok? Shall I send
a pull request?
I think all you need to is change that MT_MEMORY_RWX to be MT_MEMORY_RW.
Okay, I'll make that change.
However, I think I would also like to see the kernel text being read-only
as soon as possible - so maybe we should also have MT_MEMORY_RX, and
have map_lowmem() use this for the kernel text when we want this level
of protection?
Well, even if that's done we still need all the fixmap stuff happening
too since so many things like to change the kernel memory. :)
I'd like to start with this series, and then we can improve on it
going forward. This one seems to work and has been tested by a lot of
folks so far, so I'd hate to scrap a major portion and start over. I'd
like to get this landed, and then tweak it as needed. Does that sound
workable?
-Kees
--
Kees Cook
Chrome OS Security
This introduces CONFIG_DEBUG_RODATA, making kernel text and rodata
read-only. Additionally, this splits rodata from text so that rodata can
also be NX, which may lead to wasted memory when aligning to SECTION_SIZE.
The read-only areas are made writable during ftrace updates and kexec.
Signed-off-by: Kees Cook <redacted>
Tested-by: Laura Abbott <redacted>
Acked-by: Nicolas Pitre <redacted>
---
arch/arm/include/asm/cacheflush.h | 10 ++++++++
arch/arm/kernel/ftrace.c | 19 ++++++++++++++++
arch/arm/kernel/machine_kexec.c | 1 +
arch/arm/kernel/vmlinux.lds.S | 3 +++
arch/arm/mm/Kconfig | 12 ++++++++++
arch/arm/mm/init.c | 48 ++++++++++++++++++++++++++++++++++++++-
6 files changed, 92 insertions(+), 1 deletion(-)
@@ -486,6 +486,16 @@ int set_memory_rw(unsigned long addr, int numpages);intset_memory_x(unsignedlongaddr,intnumpages);intset_memory_nx(unsignedlongaddr,intnumpages);+#ifdef CONFIG_DEBUG_RODATA+voidmark_rodata_ro(void);+voidset_kernel_text_rw(void);+voidset_kernel_text_ro(void);+#else+staticinlinevoidset_kernel_text_rw(void){}+staticinlinevoidset_kernel_text_ro(void){}+#endif+voidflush_uprobe_xol_access(structpage*page,unsignedlonguaddr,void*kaddr,unsignedlonglen);+#endif
@@ -73,6 +90,8 @@ int ftrace_arch_code_modify_prepare(void)intftrace_arch_code_modify_post_process(void){set_all_modules_text_ro();+/* Make sure any TLB misses during machine stop are cleared. */+flush_tlb_all();return0;}
On Thu, Sep 18, 2014 at 12:19 PM, Kees Cook [off-list ref] wrote:
This is a series of patches to support CONFIG_RODATA on ARM, so that
the kernel text is RO, and non-text sections default to NX. To support
on-the-fly kernel text patching (via ftrace, kprobes, etc), fixmap
support has been finalized based on several versions of various patches
that are floating around on the mailing list. This series attempts to
include the least intrusive version, so that others can build on it for
future fixmap work.
The series has been heavily tested, and appears to be working correctly:
With CONFIG_ARM_PTDUMP, expected page table permissions are seen in
/sys/kernel/debug/kernel_page_tables.
Using CONFIG_LKDTM, the kernel now correctly detects bad accesses for
for the following lkdtm tests via /sys/kernel/debug/provoke-crash/DIRECT:
EXEC_DATA
WRITE_RO
WRITE_KERN
ftrace works:
CONFIG_FTRACE_STARTUP_TEST passes
Enabling tracing works:
echo function > /sys/kernel/debug/tracing/current_tracer
kprobes works:
CONFIG_ARM_KPROBES_TEST passes
kexec works:
kexec will load and start a new kernel
Built with and without CONFIG_HIGHMEM, CONFIG_HIGHMEM_DEBUG, and
CONFIG_NR_CPUS=32.
Thanks to everyone who has been testing this series and working on its
various pieces!
Hopefully this should address Will's last concerns. :)
Thanks!
-Kees
v6:
- always run patch_text under stop_machine (will.deacon)
- document set_fixmap's TLB flushing situation (will.deacon)
Hi Will,
Does this version look good to you? Should I turn it into a pull request?
Thanks!
-Kees
v5:
- clean up #includes in mmu.c (will.deacon)
- optimize get_cr() test (will.deacon)
- created free_tcmmem to avoid excessive #ifdefs (will.deacon)
- explicitly test irqs_disabled in set_fixmap (will.deacon)
v4:
- expanded fixmap to 3MB to support 32 CPUs (robh)
- corrected pmd-finding via vaddr instead of FIXMAP_START (robh)
- switched structure size test to BUILD_BUG_ON (sboyd)
- added locking annotations to keep sparse happy (sboyd)
- adding missing "static" declarations noticed by sparse
- reorganized fixmap portion of patches
v3:
- more cleanups in switch to generic fixmap (lauraa, robh)
- fixed kexec merge hunk glitch (will.deacon)
- added tested-by tags where appropriate from v2 testing
v2:
- fix typo in kexec merge (buildbot)
- flip index order for highmem pte access (lauraa)
- added kgdb updates (dianders)
From: Will Deacon <hidden> Date: 2014-09-26 11:21:10
On Fri, Sep 26, 2014 at 06:58:05AM +0100, Kees Cook wrote:
On Thu, Sep 18, 2014 at 12:19 PM, Kees Cook [off-list ref] wrote:
quoted
This is a series of patches to support CONFIG_RODATA on ARM, so that
the kernel text is RO, and non-text sections default to NX. To support
on-the-fly kernel text patching (via ftrace, kprobes, etc), fixmap
support has been finalized based on several versions of various patches
that are floating around on the mailing list. This series attempts to
include the least intrusive version, so that others can build on it for
future fixmap work.
The series has been heavily tested, and appears to be working correctly:
With CONFIG_ARM_PTDUMP, expected page table permissions are seen in
/sys/kernel/debug/kernel_page_tables.
Using CONFIG_LKDTM, the kernel now correctly detects bad accesses for
for the following lkdtm tests via /sys/kernel/debug/provoke-crash/DIRECT:
EXEC_DATA
WRITE_RO
WRITE_KERN
ftrace works:
CONFIG_FTRACE_STARTUP_TEST passes
Enabling tracing works:
echo function > /sys/kernel/debug/tracing/current_tracer
kprobes works:
CONFIG_ARM_KPROBES_TEST passes
kexec works:
kexec will load and start a new kernel
Built with and without CONFIG_HIGHMEM, CONFIG_HIGHMEM_DEBUG, and
CONFIG_NR_CPUS=32.
Thanks to everyone who has been testing this series and working on its
various pieces!
Hopefully this should address Will's last concerns. :)
Thanks!
-Kees
v6:
- always run patch_text under stop_machine (will.deacon)
- document set_fixmap's TLB flushing situation (will.deacon)
Hi Will,
Does this version look good to you? Should I turn it into a pull request?
The TLB flushing bits look sensible now, but the locking in __set_fixmap is
still pretty horrible (x86 just uses a mutex, not sure why we need to be
different). Still, it's Russell's call.
Will