arm64/module: deal with ambiguity in PRELxx relocation ranges [Linux 5.2]

arm64/module: deal with ambiguity in PRELxx relocation ranges [Linux 5.2]

This Linux kernel change "arm64/module: deal with ambiguity in PRELxx relocation ranges" is included in the Linux 5.2 release. This change is authored by Ard Biesheuvel <ard.biesheuvel [at] linaro.org> on Thu May 23 11:38:54 2019 +0100. The commit for this change in Linux stable tree is 1cf24a2 (patch).

arm64/module: deal with ambiguity in PRELxx relocation ranges

The R_AARCH64_PREL16 and R_AARCH64_PREL32 relocations are
documented as permitting a range of [-2^15 .. 2^16), resp.
[-2^31 .. 2^32). It is also documented that this means we
cannot detect overflow in some cases, which is bad.

Since we always interpret the targets of these relocations as
signed quantities (e.g., in the ksymtab handling code), let's
tighten the overflow checks so that targets that are out of
range for our signed interpretation of the relocated quantity
get flagged.

Signed-off-by: Ard Biesheuvel <[email protected]>
Signed-off-by: Will Deacon <[email protected]>

There are 16 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/arm64/kernel/module.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 1e418e69..f32359c 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -96,15 +96,27 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
 {
    s64 sval = do_reloc(op, place, val);

+   /*
+    * The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+    * relative relocations as having a range of [-2^15, 2^16) or
+    * [-2^31, 2^32), respectively. However, in order to be able to detect
+    * overflows reliably, we have to choose whether we interpret such
+    * quantities as signed or as unsigned, and stick with it.
+    * The way we organize our address space requires a signed
+    * interpretation of 32-bit relative references, so let's use that
+    * for all R_AARCH64_PRELxx relocations. This means our upper
+    * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+    */
+
    switch (len) {
    case 16:
        *(s16 *)place = sval;
-       if (sval < S16_MIN || sval > U16_MAX)
+       if (sval < S16_MIN || sval > S16_MAX)
            return -ERANGE;
        break;
    case 32:
        *(s32 *)place = sval;
-       if (sval < S32_MIN || sval > U32_MAX)
+       if (sval < S32_MIN || sval > S32_MAX)
            return -ERANGE;
        break;
    case 64:

Leave a Reply

Your email address will not be published. Required fields are marked *