Merge branch 'mm-readonly-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Mar 2016 23:58:50 +0000 (16:58 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Mar 2016 23:58:50 +0000 (16:58 -0700)
Pull read-only kernel memory updates from Ingo Molnar:
 "This tree adds two (security related) enhancements to the kernel's
  handling of read-only kernel memory:

   - extend read-only kernel memory to a new class of formerly writable
     kernel data: 'post-init read-only memory' via the __ro_after_init
     attribute, and mark the ARM and x86 vDSO as such read-only memory.

     This kind of attribute can be used for data that requires a once
     per bootup initialization sequence, but is otherwise never modified
     after that point.

     This feature was based on the work by PaX Team and Brad Spengler.

     (by Kees Cook, the ARM vDSO bits by David Brown.)

   - make CONFIG_DEBUG_RODATA always enabled on x86 and remove the
     Kconfig option.  This simplifies the kernel and also signals that
     read-only memory is the default model and a first-class citizen.
     (Kees Cook)"

* 'mm-readonly-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  ARM/vdso: Mark the vDSO code read-only after init
  x86/vdso: Mark the vDSO code read-only after init
  lkdtm: Verify that '__ro_after_init' works correctly
  arch: Introduce post-init read-only memory
  x86/mm: Always enable CONFIG_DEBUG_RODATA and remove the Kconfig option
  mm/init: Add 'rodata=off' boot cmdline parameter to disable read-only kernel mappings
  asm-generic: Consolidate mark_rodata_ro()

1  2 
arch/x86/mm/pageattr.c
init/main.c

diff --combined arch/x86/mm/pageattr.c
@@@ -283,7 -283,7 +283,7 @@@ static inline pgprot_t static_protectio
                   __pa_symbol(__end_rodata) >> PAGE_SHIFT))
                pgprot_val(forbidden) |= _PAGE_RW;
  
- #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+ #if defined(CONFIG_X86_64)
        /*
         * Once the kernel maps the text as RO (kernel_set_to_readonly is set),
         * kernel text mappings for the large page aligned text, rodata sections
@@@ -419,30 -419,24 +419,30 @@@ pmd_t *lookup_pmd_address(unsigned lon
  phys_addr_t slow_virt_to_phys(void *__virt_addr)
  {
        unsigned long virt_addr = (unsigned long)__virt_addr;
 -      unsigned long phys_addr, offset;
 +      phys_addr_t phys_addr;
 +      unsigned long offset;
        enum pg_level level;
        pte_t *pte;
  
        pte = lookup_address(virt_addr, &level);
        BUG_ON(!pte);
  
 +      /*
 +       * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t
 +       * before being left-shifted PAGE_SHIFT bits -- this trick is to
 +       * make 32-PAE kernel work correctly.
 +       */
        switch (level) {
        case PG_LEVEL_1G:
 -              phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
 +              phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
                offset = virt_addr & ~PUD_PAGE_MASK;
                break;
        case PG_LEVEL_2M:
 -              phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
 +              phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
                offset = virt_addr & ~PMD_PAGE_MASK;
                break;
        default:
 -              phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
 +              phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
                offset = virt_addr & ~PAGE_MASK;
        }
  
diff --combined init/main.c
@@@ -93,9 -93,6 +93,6 @@@ static int kernel_init(void *)
  extern void init_IRQ(void);
  extern void fork_init(void);
  extern void radix_tree_init(void);
- #ifndef CONFIG_DEBUG_RODATA
- static inline void mark_rodata_ro(void) { }
- #endif
  
  /*
   * Debug helper: via this flag we know that we are in 'early bootup code'
@@@ -499,6 -496,11 +496,6 @@@ asmlinkage __visible void __init start_
        char *command_line;
        char *after_dashes;
  
 -      /*
 -       * Need to run as early as possible, to initialize the
 -       * lockdep hash:
 -       */
 -      lockdep_init();
        set_task_stack_end_magic(&init_task);
        smp_setup_processor_id();
        debug_objects_early_init();
@@@ -924,6 -926,28 +921,28 @@@ static int try_to_run_init_process(cons
  
  static noinline void __init kernel_init_freeable(void);
  
+ #ifdef CONFIG_DEBUG_RODATA
+ static bool rodata_enabled = true;
+ static int __init set_debug_rodata(char *str)
+ {
+       return strtobool(str, &rodata_enabled);
+ }
+ __setup("rodata=", set_debug_rodata);
+ static void mark_readonly(void)
+ {
+       if (rodata_enabled)
+               mark_rodata_ro();
+       else
+               pr_info("Kernel memory protection disabled.\n");
+ }
+ #else
+ static inline void mark_readonly(void)
+ {
+       pr_warn("This architecture does not have kernel memory protection.\n");
+ }
+ #endif
  static int __ref kernel_init(void *unused)
  {
        int ret;
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
        free_initmem();
-       mark_rodata_ro();
+       mark_readonly();
        system_state = SYSTEM_RUNNING;
        numa_default_policy();