aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2019-05-28 10:13:16 -0400
committerWill Deacon <will.deacon@arm.com>2019-05-28 10:15:53 -0400
commit3fd00beb14a56c5ca10c3f67e5b8156f4f9223b5 (patch)
tree74c87fe15929c92b8a8368fec613b49968a11ef8
parent00377277166bac6939d8f72b429301369acaf2d8 (diff)
arm64/module: revert to unsigned interpretation of ABS16/32 relocations
Commit 1cf24a2cc3fd ("arm64/module: deal with ambiguity in PRELxx relocation ranges") updated the overflow checking logic in the relocation handling code to ensure that PREL16/32 relocations don't overflow signed quantities. However, the same code path is used for absolute relocations, where the interpretation is the opposite: the only current use case for absolute relocations operating on non-native word size quantities is the CRC32 handling in the CONFIG_MODVERSIONS code, and these CRCs are unsigned 32-bit quantities, which are now being rejected by the module loader if bit 31 happens to be set. So let's use different ranges for quanties subject to absolute vs. relative relocations: - ABS16/32 relocations should be in the range [0, Uxx_MAX) - PREL16/32 relocations should be in the range [Sxx_MIN, Sxx_MAX) - otherwise, print an error since no other 16 or 32 bit wide data relocations are currently supported. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/kernel/module.c38
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;