19
19
#include <linux/kasan.h>
20
20
#include <linux/moduleloader.h>
21
21
#include <linux/bug.h>
22
+ #include <linux/memory.h>
22
23
#include <asm/alternative.h>
23
24
#include <asm/nospec-branch.h>
24
25
#include <asm/facility.h>
@@ -174,10 +175,12 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
174
175
}
175
176
176
177
static int apply_rela_bits (Elf_Addr loc , Elf_Addr val ,
177
- int sign , int bits , int shift )
178
+ int sign , int bits , int shift ,
179
+ void * (* write )(void * dest , const void * src , size_t len ))
178
180
{
179
181
unsigned long umax ;
180
182
long min , max ;
183
+ void * dest = (void * )loc ;
181
184
182
185
if (val & ((1UL << shift ) - 1 ))
183
186
return - ENOEXEC ;
@@ -194,26 +197,33 @@ static int apply_rela_bits(Elf_Addr loc, Elf_Addr val,
194
197
return - ENOEXEC ;
195
198
}
196
199
197
- if (bits == 8 )
198
- * (unsigned char * ) loc = val ;
199
- else if (bits == 12 )
200
- * (unsigned short * ) loc = (val & 0xfff ) |
200
+ if (bits == 8 ) {
201
+ unsigned char tmp = val ;
202
+ write (dest , & tmp , 1 );
203
+ } else if (bits == 12 ) {
204
+ unsigned short tmp = (val & 0xfff ) |
201
205
(* (unsigned short * ) loc & 0xf000 );
202
- else if (bits == 16 )
203
- * (unsigned short * ) loc = val ;
204
- else if (bits == 20 )
205
- * (unsigned int * ) loc = (val & 0xfff ) << 16 |
206
- (val & 0xff000 ) >> 4 |
207
- (* (unsigned int * ) loc & 0xf00000ff );
208
- else if (bits == 32 )
209
- * (unsigned int * ) loc = val ;
210
- else if (bits == 64 )
211
- * (unsigned long * ) loc = val ;
206
+ write (dest , & tmp , 2 );
207
+ } else if (bits == 16 ) {
208
+ unsigned short tmp = val ;
209
+ write (dest , & tmp , 2 );
210
+ } else if (bits == 20 ) {
211
+ unsigned int tmp = (val & 0xfff ) << 16 |
212
+ (val & 0xff000 ) >> 4 | (* (unsigned int * ) loc & 0xf00000ff );
213
+ write (dest , & tmp , 4 );
214
+ } else if (bits == 32 ) {
215
+ unsigned int tmp = val ;
216
+ write (dest , & tmp , 4 );
217
+ } else if (bits == 64 ) {
218
+ unsigned long tmp = val ;
219
+ write (dest , & tmp , 8 );
220
+ }
212
221
return 0 ;
213
222
}
214
223
215
224
static int apply_rela (Elf_Rela * rela , Elf_Addr base , Elf_Sym * symtab ,
216
- const char * strtab , struct module * me )
225
+ const char * strtab , struct module * me ,
226
+ void * (* write )(void * dest , const void * src , size_t len ))
217
227
{
218
228
struct mod_arch_syminfo * info ;
219
229
Elf_Addr loc , val ;
@@ -241,17 +251,17 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
241
251
case R_390_64 : /* Direct 64 bit. */
242
252
val += rela -> r_addend ;
243
253
if (r_type == R_390_8 )
244
- rc = apply_rela_bits (loc , val , 0 , 8 , 0 );
254
+ rc = apply_rela_bits (loc , val , 0 , 8 , 0 , write );
245
255
else if (r_type == R_390_12 )
246
- rc = apply_rela_bits (loc , val , 0 , 12 , 0 );
256
+ rc = apply_rela_bits (loc , val , 0 , 12 , 0 , write );
247
257
else if (r_type == R_390_16 )
248
- rc = apply_rela_bits (loc , val , 0 , 16 , 0 );
258
+ rc = apply_rela_bits (loc , val , 0 , 16 , 0 , write );
249
259
else if (r_type == R_390_20 )
250
- rc = apply_rela_bits (loc , val , 1 , 20 , 0 );
260
+ rc = apply_rela_bits (loc , val , 1 , 20 , 0 , write );
251
261
else if (r_type == R_390_32 )
252
- rc = apply_rela_bits (loc , val , 0 , 32 , 0 );
262
+ rc = apply_rela_bits (loc , val , 0 , 32 , 0 , write );
253
263
else if (r_type == R_390_64 )
254
- rc = apply_rela_bits (loc , val , 0 , 64 , 0 );
264
+ rc = apply_rela_bits (loc , val , 0 , 64 , 0 , write );
255
265
break ;
256
266
case R_390_PC16 : /* PC relative 16 bit. */
257
267
case R_390_PC16DBL : /* PC relative 16 bit shifted by 1. */
@@ -260,15 +270,15 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
260
270
case R_390_PC64 : /* PC relative 64 bit. */
261
271
val += rela -> r_addend - loc ;
262
272
if (r_type == R_390_PC16 )
263
- rc = apply_rela_bits (loc , val , 1 , 16 , 0 );
273
+ rc = apply_rela_bits (loc , val , 1 , 16 , 0 , write );
264
274
else if (r_type == R_390_PC16DBL )
265
- rc = apply_rela_bits (loc , val , 1 , 16 , 1 );
275
+ rc = apply_rela_bits (loc , val , 1 , 16 , 1 , write );
266
276
else if (r_type == R_390_PC32DBL )
267
- rc = apply_rela_bits (loc , val , 1 , 32 , 1 );
277
+ rc = apply_rela_bits (loc , val , 1 , 32 , 1 , write );
268
278
else if (r_type == R_390_PC32 )
269
- rc = apply_rela_bits (loc , val , 1 , 32 , 0 );
279
+ rc = apply_rela_bits (loc , val , 1 , 32 , 0 , write );
270
280
else if (r_type == R_390_PC64 )
271
- rc = apply_rela_bits (loc , val , 1 , 64 , 0 );
281
+ rc = apply_rela_bits (loc , val , 1 , 64 , 0 , write );
272
282
break ;
273
283
case R_390_GOT12 : /* 12 bit GOT offset. */
274
284
case R_390_GOT16 : /* 16 bit GOT offset. */
@@ -283,33 +293,33 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
283
293
case R_390_GOTPLT64 : /* 64 bit offset to jump slot. */
284
294
case R_390_GOTPLTENT : /* 32 bit rel. offset to jump slot >> 1. */
285
295
if (info -> got_initialized == 0 ) {
286
- Elf_Addr * gotent ;
296
+ Elf_Addr * gotent = me -> core_layout .base +
297
+ me -> arch .got_offset +
298
+ info -> got_offset ;
287
299
288
- gotent = me -> core_layout .base + me -> arch .got_offset +
289
- info -> got_offset ;
290
- * gotent = val ;
300
+ write (gotent , & val , sizeof (* gotent ));
291
301
info -> got_initialized = 1 ;
292
302
}
293
303
val = info -> got_offset + rela -> r_addend ;
294
304
if (r_type == R_390_GOT12 ||
295
305
r_type == R_390_GOTPLT12 )
296
- rc = apply_rela_bits (loc , val , 0 , 12 , 0 );
306
+ rc = apply_rela_bits (loc , val , 0 , 12 , 0 , write );
297
307
else if (r_type == R_390_GOT16 ||
298
308
r_type == R_390_GOTPLT16 )
299
- rc = apply_rela_bits (loc , val , 0 , 16 , 0 );
309
+ rc = apply_rela_bits (loc , val , 0 , 16 , 0 , write );
300
310
else if (r_type == R_390_GOT20 ||
301
311
r_type == R_390_GOTPLT20 )
302
- rc = apply_rela_bits (loc , val , 1 , 20 , 0 );
312
+ rc = apply_rela_bits (loc , val , 1 , 20 , 0 , write );
303
313
else if (r_type == R_390_GOT32 ||
304
314
r_type == R_390_GOTPLT32 )
305
- rc = apply_rela_bits (loc , val , 0 , 32 , 0 );
315
+ rc = apply_rela_bits (loc , val , 0 , 32 , 0 , write );
306
316
else if (r_type == R_390_GOT64 ||
307
317
r_type == R_390_GOTPLT64 )
308
- rc = apply_rela_bits (loc , val , 0 , 64 , 0 );
318
+ rc = apply_rela_bits (loc , val , 0 , 64 , 0 , write );
309
319
else if (r_type == R_390_GOTENT ||
310
320
r_type == R_390_GOTPLTENT ) {
311
321
val += (Elf_Addr ) me -> core_layout .base - loc ;
312
- rc = apply_rela_bits (loc , val , 1 , 32 , 1 );
322
+ rc = apply_rela_bits (loc , val , 1 , 32 , 1 , write );
313
323
}
314
324
break ;
315
325
case R_390_PLT16DBL : /* 16 bit PC rel. PLT shifted by 1. */
@@ -320,25 +330,29 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
320
330
case R_390_PLTOFF32 : /* 32 bit offset from GOT to PLT. */
321
331
case R_390_PLTOFF64 : /* 16 bit offset from GOT to PLT. */
322
332
if (info -> plt_initialized == 0 ) {
323
- unsigned int * ip ;
324
- ip = me -> core_layout .base + me -> arch .plt_offset +
325
- info -> plt_offset ;
326
- ip [0 ] = 0x0d10e310 ; /* basr 1,0 */
327
- ip [1 ] = 0x100a0004 ; /* lg 1,10(1) */
333
+ unsigned int insn [5 ];
334
+ unsigned int * ip = me -> core_layout .base +
335
+ me -> arch .plt_offset +
336
+ info -> plt_offset ;
337
+
338
+ insn [0 ] = 0x0d10e310 ; /* basr 1,0 */
339
+ insn [1 ] = 0x100a0004 ; /* lg 1,10(1) */
328
340
if (IS_ENABLED (CONFIG_EXPOLINE ) && !nospec_disable ) {
329
341
unsigned int * ij ;
330
342
ij = me -> core_layout .base +
331
343
me -> arch .plt_offset +
332
344
me -> arch .plt_size - PLT_ENTRY_SIZE ;
333
- ip [2 ] = 0xa7f40000 + /* j __jump_r1 */
345
+ insn [2 ] = 0xa7f40000 + /* j __jump_r1 */
334
346
(unsigned int )(u16 )
335
347
(((unsigned long ) ij - 8 -
336
348
(unsigned long ) ip ) / 2 );
337
349
} else {
338
- ip [2 ] = 0x07f10000 ; /* br %r1 */
350
+ insn [2 ] = 0x07f10000 ; /* br %r1 */
339
351
}
340
- ip [3 ] = (unsigned int ) (val >> 32 );
341
- ip [4 ] = (unsigned int ) val ;
352
+ insn [3 ] = (unsigned int ) (val >> 32 );
353
+ insn [4 ] = (unsigned int ) val ;
354
+
355
+ write (ip , insn , sizeof (insn ));
342
356
info -> plt_initialized = 1 ;
343
357
}
344
358
if (r_type == R_390_PLTOFF16 ||
@@ -357,38 +371,38 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
357
371
val += rela -> r_addend - loc ;
358
372
}
359
373
if (r_type == R_390_PLT16DBL )
360
- rc = apply_rela_bits (loc , val , 1 , 16 , 1 );
374
+ rc = apply_rela_bits (loc , val , 1 , 16 , 1 , write );
361
375
else if (r_type == R_390_PLTOFF16 )
362
- rc = apply_rela_bits (loc , val , 0 , 16 , 0 );
376
+ rc = apply_rela_bits (loc , val , 0 , 16 , 0 , write );
363
377
else if (r_type == R_390_PLT32DBL )
364
- rc = apply_rela_bits (loc , val , 1 , 32 , 1 );
378
+ rc = apply_rela_bits (loc , val , 1 , 32 , 1 , write );
365
379
else if (r_type == R_390_PLT32 ||
366
380
r_type == R_390_PLTOFF32 )
367
- rc = apply_rela_bits (loc , val , 0 , 32 , 0 );
381
+ rc = apply_rela_bits (loc , val , 0 , 32 , 0 , write );
368
382
else if (r_type == R_390_PLT64 ||
369
383
r_type == R_390_PLTOFF64 )
370
- rc = apply_rela_bits (loc , val , 0 , 64 , 0 );
384
+ rc = apply_rela_bits (loc , val , 0 , 64 , 0 , write );
371
385
break ;
372
386
case R_390_GOTOFF16 : /* 16 bit offset to GOT. */
373
387
case R_390_GOTOFF32 : /* 32 bit offset to GOT. */
374
388
case R_390_GOTOFF64 : /* 64 bit offset to GOT. */
375
389
val = val + rela -> r_addend -
376
390
((Elf_Addr ) me -> core_layout .base + me -> arch .got_offset );
377
391
if (r_type == R_390_GOTOFF16 )
378
- rc = apply_rela_bits (loc , val , 0 , 16 , 0 );
392
+ rc = apply_rela_bits (loc , val , 0 , 16 , 0 , write );
379
393
else if (r_type == R_390_GOTOFF32 )
380
- rc = apply_rela_bits (loc , val , 0 , 32 , 0 );
394
+ rc = apply_rela_bits (loc , val , 0 , 32 , 0 , write );
381
395
else if (r_type == R_390_GOTOFF64 )
382
- rc = apply_rela_bits (loc , val , 0 , 64 , 0 );
396
+ rc = apply_rela_bits (loc , val , 0 , 64 , 0 , write );
383
397
break ;
384
398
case R_390_GOTPC : /* 32 bit PC relative offset to GOT. */
385
399
case R_390_GOTPCDBL : /* 32 bit PC rel. off. to GOT shifted by 1. */
386
400
val = (Elf_Addr ) me -> core_layout .base + me -> arch .got_offset +
387
401
rela -> r_addend - loc ;
388
402
if (r_type == R_390_GOTPC )
389
- rc = apply_rela_bits (loc , val , 1 , 32 , 0 );
403
+ rc = apply_rela_bits (loc , val , 1 , 32 , 0 , write );
390
404
else if (r_type == R_390_GOTPCDBL )
391
- rc = apply_rela_bits (loc , val , 1 , 32 , 1 );
405
+ rc = apply_rela_bits (loc , val , 1 , 32 , 1 , write );
392
406
break ;
393
407
case R_390_COPY :
394
408
case R_390_GLOB_DAT : /* Create GOT entry. */
@@ -412,9 +426,10 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
412
426
return 0 ;
413
427
}
414
428
415
- int apply_relocate_add (Elf_Shdr * sechdrs , const char * strtab ,
429
+ static int __apply_relocate_add (Elf_Shdr * sechdrs , const char * strtab ,
416
430
unsigned int symindex , unsigned int relsec ,
417
- struct module * me )
431
+ struct module * me ,
432
+ void * (* write )(void * dest , const void * src , size_t len ))
418
433
{
419
434
Elf_Addr base ;
420
435
Elf_Sym * symtab ;
@@ -430,13 +445,27 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
430
445
n = sechdrs [relsec ].sh_size / sizeof (Elf_Rela );
431
446
432
447
for (i = 0 ; i < n ; i ++ , rela ++ ) {
433
- rc = apply_rela (rela , base , symtab , strtab , me );
448
+ rc = apply_rela (rela , base , symtab , strtab , me , write );
434
449
if (rc )
435
450
return rc ;
436
451
}
437
452
return 0 ;
438
453
}
439
454
455
+ int apply_relocate_add (Elf_Shdr * sechdrs , const char * strtab ,
456
+ unsigned int symindex , unsigned int relsec ,
457
+ struct module * me )
458
+ {
459
+ bool early = me -> state == MODULE_STATE_UNFORMED ;
460
+ void * (* write )(void * , const void * , size_t ) = memcpy ;
461
+
462
+ if (!early )
463
+ write = s390_kernel_write ;
464
+
465
+ return __apply_relocate_add (sechdrs , strtab , symindex , relsec , me ,
466
+ write );
467
+ }
468
+
440
469
int module_finalize (const Elf_Ehdr * hdr ,
441
470
const Elf_Shdr * sechdrs ,
442
471
struct module * me )
0 commit comments