Skip to content

Commit be24226

Browse files
Peter ZijlstraJiri Kosina
authored andcommitted
s390/module: Use s390_kernel_write() for late relocations
Because of late module patching, a livepatch module needs to be able to apply some of its relocations well after it has been loaded. Instead of playing games with module_{dis,en}able_ro(), use existing text poking mechanisms to apply relocations after module loading. So far only x86, s390 and Power have HAVE_LIVEPATCH but only the first two also have STRICT_MODULE_RWX. This will allow removal of the last module_disable_ro() usage in livepatch. The ultimate goal is to completely disallow making executable mappings writable. [ jpoimboe: Split up patches. Use mod state to determine whether memcpy() can be used. Test and add fixes. ] Cc: [email protected] Cc: Heiko Carstens <[email protected]> Cc: Gerald Schaefer <[email protected]> Cc: Christian Borntraeger <[email protected]> Suggested-by: Josh Poimboeuf <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Josh Poimboeuf <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Joe Lawrence <[email protected]> Acked-by: Miroslav Benes <[email protected]> Acked-by: Gerald Schaefer <[email protected]> # s390 Signed-off-by: Jiri Kosina <[email protected]>
1 parent cb2ccea commit be24226

File tree

1 file changed

+88
-59
lines changed

1 file changed

+88
-59
lines changed

arch/s390/kernel/module.c

Lines changed: 88 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/kasan.h>
2020
#include <linux/moduleloader.h>
2121
#include <linux/bug.h>
22+
#include <linux/memory.h>
2223
#include <asm/alternative.h>
2324
#include <asm/nospec-branch.h>
2425
#include <asm/facility.h>
@@ -174,10 +175,12 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
174175
}
175176

176177
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))
178180
{
179181
unsigned long umax;
180182
long min, max;
183+
void *dest = (void *)loc;
181184

182185
if (val & ((1UL << shift) - 1))
183186
return -ENOEXEC;
@@ -194,26 +197,33 @@ static int apply_rela_bits(Elf_Addr loc, Elf_Addr val,
194197
return -ENOEXEC;
195198
}
196199

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) |
201205
(*(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+
}
212221
return 0;
213222
}
214223

215224
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))
217227
{
218228
struct mod_arch_syminfo *info;
219229
Elf_Addr loc, val;
@@ -241,17 +251,17 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
241251
case R_390_64: /* Direct 64 bit. */
242252
val += rela->r_addend;
243253
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);
245255
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);
247257
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);
249259
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);
251261
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);
253263
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);
255265
break;
256266
case R_390_PC16: /* PC relative 16 bit. */
257267
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,
260270
case R_390_PC64: /* PC relative 64 bit. */
261271
val += rela->r_addend - loc;
262272
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);
264274
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);
266276
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);
268278
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);
270280
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);
272282
break;
273283
case R_390_GOT12: /* 12 bit GOT offset. */
274284
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,
283293
case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
284294
case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
285295
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;
287299

288-
gotent = me->core_layout.base + me->arch.got_offset +
289-
info->got_offset;
290-
*gotent = val;
300+
write(gotent, &val, sizeof(*gotent));
291301
info->got_initialized = 1;
292302
}
293303
val = info->got_offset + rela->r_addend;
294304
if (r_type == R_390_GOT12 ||
295305
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);
297307
else if (r_type == R_390_GOT16 ||
298308
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);
300310
else if (r_type == R_390_GOT20 ||
301311
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);
303313
else if (r_type == R_390_GOT32 ||
304314
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);
306316
else if (r_type == R_390_GOT64 ||
307317
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);
309319
else if (r_type == R_390_GOTENT ||
310320
r_type == R_390_GOTPLTENT) {
311321
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);
313323
}
314324
break;
315325
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,
320330
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
321331
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
322332
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) */
328340
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
329341
unsigned int *ij;
330342
ij = me->core_layout.base +
331343
me->arch.plt_offset +
332344
me->arch.plt_size - PLT_ENTRY_SIZE;
333-
ip[2] = 0xa7f40000 + /* j __jump_r1 */
345+
insn[2] = 0xa7f40000 + /* j __jump_r1 */
334346
(unsigned int)(u16)
335347
(((unsigned long) ij - 8 -
336348
(unsigned long) ip) / 2);
337349
} else {
338-
ip[2] = 0x07f10000; /* br %r1 */
350+
insn[2] = 0x07f10000; /* br %r1 */
339351
}
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));
342356
info->plt_initialized = 1;
343357
}
344358
if (r_type == R_390_PLTOFF16 ||
@@ -357,38 +371,38 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
357371
val += rela->r_addend - loc;
358372
}
359373
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);
361375
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);
363377
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);
365379
else if (r_type == R_390_PLT32 ||
366380
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);
368382
else if (r_type == R_390_PLT64 ||
369383
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);
371385
break;
372386
case R_390_GOTOFF16: /* 16 bit offset to GOT. */
373387
case R_390_GOTOFF32: /* 32 bit offset to GOT. */
374388
case R_390_GOTOFF64: /* 64 bit offset to GOT. */
375389
val = val + rela->r_addend -
376390
((Elf_Addr) me->core_layout.base + me->arch.got_offset);
377391
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);
379393
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);
381395
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);
383397
break;
384398
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
385399
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
386400
val = (Elf_Addr) me->core_layout.base + me->arch.got_offset +
387401
rela->r_addend - loc;
388402
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);
390404
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);
392406
break;
393407
case R_390_COPY:
394408
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,
412426
return 0;
413427
}
414428

415-
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
429+
static int __apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
416430
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))
418433
{
419434
Elf_Addr base;
420435
Elf_Sym *symtab;
@@ -430,13 +445,27 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
430445
n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
431446

432447
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);
434449
if (rc)
435450
return rc;
436451
}
437452
return 0;
438453
}
439454

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+
440469
int module_finalize(const Elf_Ehdr *hdr,
441470
const Elf_Shdr *sechdrs,
442471
struct module *me)

0 commit comments

Comments
 (0)