aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2016-01-05 04:18:52 -0500
committerWill Deacon <will.deacon@arm.com>2016-01-05 06:27:20 -0500
commitf930896967fa3f9ab16a6f87267b92798308d48f (patch)
tree053df1f97b3a6f2195716ab30e5ffc747a80d234
parentb24a557527f97ad88619d5bd4c8017c635056d69 (diff)
arm64: module: avoid undefined shift behavior in reloc_data()
Compilers may engage the improbability drive when encountering shifts by a distance that is a multiple of the size of the operand type. Since the required bounds check is very simple here, we can get rid of all the fuzzy masking, shifting and comparing, and use the documented bounds directly. Reported-by: David Binderman <dcb314@hotmail.com> 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.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)
72 72
73static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 73static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
74{ 74{
75 u64 imm_mask = (1 << len) - 1;
76 s64 sval = do_reloc(op, place, val); 75 s64 sval = do_reloc(op, place, val);
77 76
78 switch (len) { 77 switch (len) {
79 case 16: 78 case 16:
80 *(s16 *)place = sval; 79 *(s16 *)place = sval;
80 if (sval < S16_MIN || sval > U16_MAX)
81 return -ERANGE;
81 break; 82 break;
82 case 32: 83 case 32:
83 *(s32 *)place = sval; 84 *(s32 *)place = sval;
85 if (sval < S32_MIN || sval > U32_MAX)
86 return -ERANGE;
84 break; 87 break;
85 case 64: 88 case 64:
86 *(s64 *)place = sval; 89 *(s64 *)place = sval;
@@ -89,21 +92,6 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
89 pr_err("Invalid length (%d) for data relocation\n", len); 92 pr_err("Invalid length (%d) for data relocation\n", len);
90 return 0; 93 return 0;
91 } 94 }
92
93 /*
94 * Extract the upper value bits (including the sign bit) and
95 * shift them to bit 0.
96 */
97 sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
98
99 /*
100 * Overflow has occurred if the value is not representable in
101 * len bits (i.e the bottom len bits are not sign-extended and
102 * the top bits are not all zero).
103 */
104 if ((u64)(sval + 1) > 2)
105 return -ERANGE;
106
107 return 0; 95 return 0;
108} 96}
109 97