aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2016-07-25 15:16:55 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-07-25 15:16:55 +0000
commit8e31bb4d9cf427f6a1720e975887dadb46a60057 (patch)
treed1f55e2f55f7c5eb790b609621d32652c6c35c5f
parent329293910e5b9e0d60575895d52de97b1febfa5e (diff)
parent2cd5629f66e2d55b17d9c66affeccf2eb2027ef1 (diff)
downloadv4.4-8e31bb4d9cf427f6a1720e975887dadb46a60057.tar.gz
UPSTREAM: arm64: module: avoid undefined shift behavior in reloc_data()
am: 2cd5629f66 Change-Id: Ia1363a813f3b5473fc8a09eac08d1bfd8a26b8a2
-rw-r--r--arch/arm64/kernel/module.c20
1 files changed, 4 insertions, 16 deletions
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 03464ab0fff2..93e970231ca9 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -72,15 +72,18 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val)
static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
{
- u64 imm_mask = (1 << len) - 1;
s64 sval = do_reloc(op, place, val);
switch (len) {
case 16:
*(s16 *)place = sval;
+ if (sval < S16_MIN || sval > U16_MAX)
+ return -ERANGE;
break;
case 32:
*(s32 *)place = sval;
+ if (sval < S32_MIN || sval > U32_MAX)
+ return -ERANGE;
break;
case 64:
*(s64 *)place = sval;
@@ -89,21 +92,6 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
pr_err("Invalid length (%d) for data relocation\n", len);
return 0;
}
-
- /*
- * Extract the upper value bits (including the sign bit) and
- * shift them to bit 0.
- */
- sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
-
- /*
- * Overflow has occurred if the value is not representable in
- * len bits (i.e the bottom len bits are not sign-extended and
- * the top bits are not all zero).
- */
- if ((u64)(sval + 1) > 2)
- return -ERANGE;
-
return 0;
}