diff options
Diffstat (limited to 'arch/arm64/kernel/module.c')
| -rw-r--r-- | arch/arm64/kernel/module.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index f32359cffb01..dd080837e6a9 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c | |||
| @@ -98,10 +98,10 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) | |||
| 98 | 98 | ||
| 99 | /* | 99 | /* |
| 100 | * The ELF psABI for AArch64 documents the 16-bit and 32-bit place | 100 | * The ELF psABI for AArch64 documents the 16-bit and 32-bit place |
| 101 | * relative relocations as having a range of [-2^15, 2^16) or | 101 | * relative and absolute relocations as having a range of [-2^15, 2^16) |
| 102 | * [-2^31, 2^32), respectively. However, in order to be able to detect | 102 | * or [-2^31, 2^32), respectively. However, in order to be able to |
| 103 | * overflows reliably, we have to choose whether we interpret such | 103 | * detect overflows reliably, we have to choose whether we interpret |
| 104 | * quantities as signed or as unsigned, and stick with it. | 104 | * such quantities as signed or as unsigned, and stick with it. |
| 105 | * The way we organize our address space requires a signed | 105 | * The way we organize our address space requires a signed |
| 106 | * interpretation of 32-bit relative references, so let's use that | 106 | * interpretation of 32-bit relative references, so let's use that |
| 107 | * for all R_AARCH64_PRELxx relocations. This means our upper | 107 | * for all R_AARCH64_PRELxx relocations. This means our upper |
| @@ -111,13 +111,35 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) | |||
| 111 | switch (len) { | 111 | switch (len) { |
| 112 | case 16: | 112 | case 16: |
| 113 | *(s16 *)place = sval; | 113 | *(s16 *)place = sval; |
| 114 | if (sval < S16_MIN || sval > S16_MAX) | 114 | switch (op) { |
| 115 | return -ERANGE; | 115 | case RELOC_OP_ABS: |
| 116 | if (sval < 0 || sval > U16_MAX) | ||
| 117 | return -ERANGE; | ||
| 118 | break; | ||
| 119 | case RELOC_OP_PREL: | ||
| 120 | if (sval < S16_MIN || sval > S16_MAX) | ||
| 121 | return -ERANGE; | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | pr_err("Invalid 16-bit data relocation (%d)\n", op); | ||
| 125 | return 0; | ||
| 126 | } | ||
| 116 | break; | 127 | break; |
| 117 | case 32: | 128 | case 32: |
| 118 | *(s32 *)place = sval; | 129 | *(s32 *)place = sval; |
| 119 | if (sval < S32_MIN || sval > S32_MAX) | 130 | switch (op) { |
| 120 | return -ERANGE; | 131 | case RELOC_OP_ABS: |
| 132 | if (sval < 0 || sval > U32_MAX) | ||
| 133 | return -ERANGE; | ||
| 134 | break; | ||
| 135 | case RELOC_OP_PREL: | ||
| 136 | if (sval < S32_MIN || sval > S32_MAX) | ||
| 137 | return -ERANGE; | ||
| 138 | break; | ||
| 139 | default: | ||
| 140 | pr_err("Invalid 32-bit data relocation (%d)\n", op); | ||
| 141 | return 0; | ||
| 142 | } | ||
| 121 | break; | 143 | break; |
| 122 | case 64: | 144 | case 64: |
| 123 | *(s64 *)place = sval; | 145 | *(s64 *)place = sval; |
