@@ -711,6 +711,24 @@ enum cfi_mode {
711711};
712712
713713static enum cfi_mode cfi_mode __ro_after_init = CFI_DEFAULT ;
714+ static bool cfi_rand __ro_after_init = true;
715+ static u32 cfi_seed __ro_after_init ;
716+
717+ /*
718+ * Re-hash the CFI hash with a boot-time seed while making sure the result is
719+ * not a valid ENDBR instruction.
720+ */
721+ static u32 cfi_rehash (u32 hash )
722+ {
723+ hash ^= cfi_seed ;
724+ while (unlikely (is_endbr (hash ) || is_endbr (- hash ))) {
725+ bool lsb = hash & 1 ;
726+ hash >>= 1 ;
727+ if (lsb )
728+ hash ^= 0x80200003 ;
729+ }
730+ return hash ;
731+ }
714732
715733static __init int cfi_parse_cmdline (char * str )
716734{
@@ -728,10 +746,13 @@ static __init int cfi_parse_cmdline(char *str)
728746 cfi_mode = CFI_DEFAULT ;
729747 } else if (!strcmp (str , "off" )) {
730748 cfi_mode = CFI_OFF ;
749+ cfi_rand = false;
731750 } else if (!strcmp (str , "kcfi" )) {
732751 cfi_mode = CFI_KCFI ;
733752 } else if (!strcmp (str , "fineibt" )) {
734753 cfi_mode = CFI_FINEIBT ;
754+ } else if (!strcmp (str , "norand" )) {
755+ cfi_rand = false;
735756 } else {
736757 pr_err ("Ignoring unknown cfi option (%s)." , str );
737758 }
@@ -856,7 +877,50 @@ static int cfi_disable_callers(s32 *start, s32 *end)
856877 return 0 ;
857878}
858879
880+ static int cfi_enable_callers (s32 * start , s32 * end )
881+ {
882+ /*
883+ * Re-enable kCFI, undo what cfi_disable_callers() did.
884+ */
885+ const u8 mov [] = { 0x41 , 0xba };
886+ s32 * s ;
887+
888+ for (s = start ; s < end ; s ++ ) {
889+ void * addr = (void * )s + * s ;
890+ u32 hash ;
891+
892+ addr -= fineibt_caller_size ;
893+ hash = decode_caller_hash (addr );
894+ if (!hash ) /* nocfi callers */
895+ continue ;
896+
897+ text_poke_early (addr , mov , 2 );
898+ }
899+
900+ return 0 ;
901+ }
902+
859903/* .cfi_sites */
904+ static int cfi_rand_preamble (s32 * start , s32 * end )
905+ {
906+ s32 * s ;
907+
908+ for (s = start ; s < end ; s ++ ) {
909+ void * addr = (void * )s + * s ;
910+ u32 hash ;
911+
912+ hash = decode_preamble_hash (addr );
913+ if (WARN (!hash , "no CFI hash found at: %pS %px %*ph\n" ,
914+ addr , addr , 5 , addr ))
915+ return - EINVAL ;
916+
917+ hash = cfi_rehash (hash );
918+ text_poke_early (addr + 1 , & hash , 4 );
919+ }
920+
921+ return 0 ;
922+ }
923+
860924static int cfi_rewrite_preamble (s32 * start , s32 * end )
861925{
862926 s32 * s ;
@@ -879,6 +943,25 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
879943}
880944
881945/* .retpoline_sites */
946+ static int cfi_rand_callers (s32 * start , s32 * end )
947+ {
948+ s32 * s ;
949+
950+ for (s = start ; s < end ; s ++ ) {
951+ void * addr = (void * )s + * s ;
952+ u32 hash ;
953+
954+ addr -= fineibt_caller_size ;
955+ hash = decode_caller_hash (addr );
956+ if (hash ) {
957+ hash = - cfi_rehash (hash );
958+ text_poke_early (addr + 2 , & hash , 4 );
959+ }
960+ }
961+
962+ return 0 ;
963+ }
964+
882965static int cfi_rewrite_callers (s32 * start , s32 * end )
883966{
884967 s32 * s ;
@@ -915,31 +998,44 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
915998 cfi_mode = CFI_FINEIBT ;
916999 }
9171000
918- switch (cfi_mode ) {
919- case CFI_OFF :
920- ret = cfi_disable_callers (start_retpoline , end_retpoline );
1001+ /*
1002+ * Rewrite the callers to not use the __cfi_ stubs, such that we might
1003+ * rewrite them. This disables all CFI. If this succeeds but any of the
1004+ * later stages fails, we're without CFI.
1005+ */
1006+ ret = cfi_disable_callers (start_retpoline , end_retpoline );
1007+ if (ret )
1008+ goto err ;
1009+
1010+ if (cfi_rand ) {
1011+ if (builtin )
1012+ cfi_seed = get_random_u32 ();
1013+
1014+ ret = cfi_rand_preamble (start_cfi , end_cfi );
9211015 if (ret )
9221016 goto err ;
9231017
1018+ ret = cfi_rand_callers (start_retpoline , end_retpoline );
1019+ if (ret )
1020+ goto err ;
1021+ }
1022+
1023+ switch (cfi_mode ) {
1024+ case CFI_OFF :
9241025 if (builtin )
9251026 pr_info ("Disabling CFI\n" );
9261027 return ;
9271028
9281029 case CFI_KCFI :
1030+ ret = cfi_enable_callers (start_retpoline , end_retpoline );
1031+ if (ret )
1032+ goto err ;
1033+
9291034 if (builtin )
9301035 pr_info ("Using kCFI\n" );
9311036 return ;
9321037
9331038 case CFI_FINEIBT :
934- /*
935- * Rewrite the callers to not use the __cfi_ stubs, such that we might
936- * rewrite them. This disables all CFI. If this succeeds but any of the
937- * later stages fails, we're without CFI.
938- */
939- ret = cfi_disable_callers (start_retpoline , end_retpoline );
940- if (ret )
941- goto err ;
942-
9431039 ret = cfi_rewrite_preamble (start_cfi , end_cfi );
9441040 if (ret )
9451041 goto err ;
0 commit comments