@@ -994,7 +994,21 @@ static inline void unuse_temporary_mm(temp_mm_state_t prev_state)
994
994
__ro_after_init struct mm_struct * poking_mm ;
995
995
__ro_after_init unsigned long poking_addr ;
996
996
997
- static void * __text_poke (void * addr , const void * opcode , size_t len )
997
+ static void text_poke_memcpy (void * dst , const void * src , size_t len )
998
+ {
999
+ memcpy (dst , src , len );
1000
+ }
1001
+
1002
+ static void text_poke_memset (void * dst , const void * src , size_t len )
1003
+ {
1004
+ int c = * (const int * )src ;
1005
+
1006
+ memset (dst , c , len );
1007
+ }
1008
+
1009
+ typedef void text_poke_f (void * dst , const void * src , size_t len );
1010
+
1011
+ static void * __text_poke (text_poke_f func , void * addr , const void * src , size_t len )
998
1012
{
999
1013
bool cross_page_boundary = offset_in_page (addr ) + len > PAGE_SIZE ;
1000
1014
struct page * pages [2 ] = {NULL };
@@ -1059,7 +1073,7 @@ static void *__text_poke(void *addr, const void *opcode, size_t len)
1059
1073
prev = use_temporary_mm (poking_mm );
1060
1074
1061
1075
kasan_disable_current ();
1062
- memcpy ((u8 * )poking_addr + offset_in_page (addr ), opcode , len );
1076
+ func ((u8 * )poking_addr + offset_in_page (addr ), src , len );
1063
1077
kasan_enable_current ();
1064
1078
1065
1079
/*
@@ -1087,11 +1101,13 @@ static void *__text_poke(void *addr, const void *opcode, size_t len)
1087
1101
(cross_page_boundary ? 2 : 1 ) * PAGE_SIZE ,
1088
1102
PAGE_SHIFT , false);
1089
1103
1090
- /*
1091
- * If the text does not match what we just wrote then something is
1092
- * fundamentally screwy; there's nothing we can really do about that.
1093
- */
1094
- BUG_ON (memcmp (addr , opcode , len ));
1104
+ if (func == text_poke_memcpy ) {
1105
+ /*
1106
+ * If the text does not match what we just wrote then something is
1107
+ * fundamentally screwy; there's nothing we can really do about that.
1108
+ */
1109
+ BUG_ON (memcmp (addr , src , len ));
1110
+ }
1095
1111
1096
1112
local_irq_restore (flags );
1097
1113
pte_unmap_unlock (ptep , ptl );
@@ -1118,7 +1134,7 @@ void *text_poke(void *addr, const void *opcode, size_t len)
1118
1134
{
1119
1135
lockdep_assert_held (& text_mutex );
1120
1136
1121
- return __text_poke (addr , opcode , len );
1137
+ return __text_poke (text_poke_memcpy , addr , opcode , len );
1122
1138
}
1123
1139
1124
1140
/**
@@ -1137,7 +1153,7 @@ void *text_poke(void *addr, const void *opcode, size_t len)
1137
1153
*/
1138
1154
void * text_poke_kgdb (void * addr , const void * opcode , size_t len )
1139
1155
{
1140
- return __text_poke (addr , opcode , len );
1156
+ return __text_poke (text_poke_memcpy , addr , opcode , len );
1141
1157
}
1142
1158
1143
1159
/**
@@ -1167,7 +1183,38 @@ void *text_poke_copy(void *addr, const void *opcode, size_t len)
1167
1183
1168
1184
s = min_t (size_t , PAGE_SIZE * 2 - offset_in_page (ptr ), len - patched );
1169
1185
1170
- __text_poke ((void * )ptr , opcode + patched , s );
1186
+ __text_poke (text_poke_memcpy , (void * )ptr , opcode + patched , s );
1187
+ patched += s ;
1188
+ }
1189
+ mutex_unlock (& text_mutex );
1190
+ return addr ;
1191
+ }
1192
+
1193
+ /**
1194
+ * text_poke_set - memset into (an unused part of) RX memory
1195
+ * @addr: address to modify
1196
+ * @c: the byte to fill the area with
1197
+ * @len: length to copy, could be more than 2x PAGE_SIZE
1198
+ *
1199
+ * This is useful to overwrite unused regions of RX memory with illegal
1200
+ * instructions.
1201
+ */
1202
+ void * text_poke_set (void * addr , int c , size_t len )
1203
+ {
1204
+ unsigned long start = (unsigned long )addr ;
1205
+ size_t patched = 0 ;
1206
+
1207
+ if (WARN_ON_ONCE (core_kernel_text (start )))
1208
+ return NULL ;
1209
+
1210
+ mutex_lock (& text_mutex );
1211
+ while (patched < len ) {
1212
+ unsigned long ptr = start + patched ;
1213
+ size_t s ;
1214
+
1215
+ s = min_t (size_t , PAGE_SIZE * 2 - offset_in_page (ptr ), len - patched );
1216
+
1217
+ __text_poke (text_poke_memset , (void * )ptr , (void * )& c , s );
1171
1218
patched += s ;
1172
1219
}
1173
1220
mutex_unlock (& text_mutex );
0 commit comments