@@ -783,6 +783,61 @@ void __init_or_module text_poke_early(void *addr, const void *opcode,
783
783
}
784
784
}
785
785
786
+ typedef struct {
787
+ struct mm_struct * mm ;
788
+ } temp_mm_state_t ;
789
+
790
+ /*
791
+ * Using a temporary mm allows to set temporary mappings that are not accessible
792
+ * by other CPUs. Such mappings are needed to perform sensitive memory writes
793
+ * that override the kernel memory protections (e.g., W^X), without exposing the
794
+ * temporary page-table mappings that are required for these write operations to
795
+ * other CPUs. Using a temporary mm also allows to avoid TLB shootdowns when the
796
+ * mapping is torn down.
797
+ *
798
+ * Context: The temporary mm needs to be used exclusively by a single core. To
799
+ * harden security IRQs must be disabled while the temporary mm is
800
+ * loaded, thereby preventing interrupt handler bugs from overriding
801
+ * the kernel memory protection.
802
+ */
803
+ static inline temp_mm_state_t use_temporary_mm (struct mm_struct * mm )
804
+ {
805
+ temp_mm_state_t temp_state ;
806
+
807
+ lockdep_assert_irqs_disabled ();
808
+ temp_state .mm = this_cpu_read (cpu_tlbstate .loaded_mm );
809
+ switch_mm_irqs_off (NULL , mm , current );
810
+
811
+ /*
812
+ * If breakpoints are enabled, disable them while the temporary mm is
813
+ * used. Userspace might set up watchpoints on addresses that are used
814
+ * in the temporary mm, which would lead to wrong signals being sent or
815
+ * crashes.
816
+ *
817
+ * Note that breakpoints are not disabled selectively, which also causes
818
+ * kernel breakpoints (e.g., perf's) to be disabled. This might be
819
+ * undesirable, but still seems reasonable as the code that runs in the
820
+ * temporary mm should be short.
821
+ */
822
+ if (hw_breakpoint_active ())
823
+ hw_breakpoint_disable ();
824
+
825
+ return temp_state ;
826
+ }
827
+
828
+ static inline void unuse_temporary_mm (temp_mm_state_t prev_state )
829
+ {
830
+ lockdep_assert_irqs_disabled ();
831
+ switch_mm_irqs_off (NULL , prev_state .mm , current );
832
+
833
+ /*
834
+ * Restore the breakpoints if they were disabled before the temporary mm
835
+ * was loaded.
836
+ */
837
+ if (hw_breakpoint_active ())
838
+ hw_breakpoint_restore ();
839
+ }
840
+
786
841
__ro_after_init struct mm_struct * poking_mm ;
787
842
__ro_after_init unsigned long poking_addr ;
788
843
0 commit comments