diff options
| author | Mark Hatle <mark.hatle@amd.com> | 2024-05-24 14:12:14 -0600 |
|---|---|---|
| committer | Steve Sakoman <steve@sakoman.com> | 2024-06-05 05:57:12 -0700 |
| commit | 59c0a35bb829217bf9b36d6a782ba88b344fed51 (patch) | |
| tree | dd528f7b1d9394c1b2b77112f4f5bca91e84b929 | |
| parent | 96b48c195a60ef6de2a43a66a8fa61b6a4baff10 (diff) | |
| download | poky-59c0a35bb829217bf9b36d6a782ba88b344fed51.tar.gz | |
gcc: Fix for CVE-2024-0151
Fix for insufficient argument checking in Secure state Entry functions
in software using Cortex-M Security Extensions (CMSE), that has been
compiled using toolchains that implement 'Arm v8-M Security Extensions
Requirements on Development Tools' prior to version 1.4, allows an
attacker to pass values to Secure state that are out of range for types
smaller than 32-bits. Out of range values might lead to incorrect
operations in secure state.
(From OE-Core rev: 165a7007678c27b6c0a27cda25652a00768c2fee)
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
| -rw-r--r-- | meta/recipes-devtools/gcc/gcc-13.2.inc | 1 | ||||
| -rw-r--r-- | meta/recipes-devtools/gcc/gcc/CVE-2024-0151.patch | 315 |
2 files changed, 316 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-13.2.inc b/meta/recipes-devtools/gcc/gcc-13.2.inc index 603377a49a..abf177822b 100644 --- a/meta/recipes-devtools/gcc/gcc-13.2.inc +++ b/meta/recipes-devtools/gcc/gcc-13.2.inc | |||
| @@ -68,6 +68,7 @@ SRC_URI = "${BASEURI} \ | |||
| 68 | file://CVE-2023-4039.patch \ | 68 | file://CVE-2023-4039.patch \ |
| 69 | file://0026-aarch64-Fix-loose-ldpstp-check-PR111411.patch \ | 69 | file://0026-aarch64-Fix-loose-ldpstp-check-PR111411.patch \ |
| 70 | file://0027-Fix-gcc-vect-module-testcases.patch \ | 70 | file://0027-Fix-gcc-vect-module-testcases.patch \ |
| 71 | file://CVE-2024-0151.patch \ | ||
| 71 | " | 72 | " |
| 72 | SRC_URI[sha256sum] = "e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da" | 73 | SRC_URI[sha256sum] = "e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da" |
| 73 | 74 | ||
diff --git a/meta/recipes-devtools/gcc/gcc/CVE-2024-0151.patch b/meta/recipes-devtools/gcc/gcc/CVE-2024-0151.patch new file mode 100644 index 0000000000..12883388cb --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc/CVE-2024-0151.patch | |||
| @@ -0,0 +1,315 @@ | |||
| 1 | arm: Zero/Sign extends for CMSE security | ||
| 2 | |||
| 3 | This patch makes the following changes: | ||
| 4 | |||
| 5 | 1) When calling a secure function from non-secure code then any arguments | ||
| 6 | smaller than 32-bits that are passed in registers are zero- or sign-extended. | ||
| 7 | 2) After a non-secure function returns into secure code then any return value | ||
| 8 | smaller than 32-bits that is passed in a register is zero- or sign-extended. | ||
| 9 | |||
| 10 | This patch addresses the following CVE-2024-0151. | ||
| 11 | |||
| 12 | gcc/ChangeLog: | ||
| 13 | PR target/114837 | ||
| 14 | * config/arm/arm.cc (cmse_nonsecure_call_inline_register_clear): | ||
| 15 | Add zero/sign extend. | ||
| 16 | (arm_expand_prologue): Add zero/sign extend. | ||
| 17 | |||
| 18 | gcc/testsuite/ChangeLog: | ||
| 19 | |||
| 20 | * gcc.target/arm/cmse/extend-param.c: New test. | ||
| 21 | * gcc.target/arm/cmse/extend-return.c: New test. | ||
| 22 | |||
| 23 | CVE: CVE-2024-0151 | ||
| 24 | Upstream-Status: Backport [https://gcc.gnu.org/pipermail/gcc-patches/2024-April/649973.html] | ||
| 25 | Signed-off-by: Mark Hatle <mark.hatle@amd.com> | ||
| 26 | |||
| 27 | diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc | ||
| 28 | index 0217abc218d60956ce727e6d008d46b9176dddc5..ea0c963a4d67ecd70e1571624e84dfe46d757df9 100644 | ||
| 29 | --- a/gcc/config/arm/arm.cc | ||
| 30 | +++ b/gcc/config/arm/arm.cc | ||
| 31 | @@ -19210,6 +19210,30 @@ cmse_nonsecure_call_inline_register_clear (void) | ||
| 32 | end_sequence (); | ||
| 33 | emit_insn_before (seq, insn); | ||
| 34 | |||
| 35 | + /* The AAPCS requires the callee to widen integral types narrower | ||
| 36 | + than 32 bits to the full width of the register; but when handling | ||
| 37 | + calls to non-secure space, we cannot trust the callee to have | ||
| 38 | + correctly done so. So forcibly re-widen the result here. */ | ||
| 39 | + tree ret_type = TREE_TYPE (fntype); | ||
| 40 | + if ((TREE_CODE (ret_type) == INTEGER_TYPE | ||
| 41 | + || TREE_CODE (ret_type) == ENUMERAL_TYPE | ||
| 42 | + || TREE_CODE (ret_type) == BOOLEAN_TYPE) | ||
| 43 | + && known_lt (GET_MODE_SIZE (TYPE_MODE (ret_type)), 4)) | ||
| 44 | + { | ||
| 45 | + machine_mode ret_mode = TYPE_MODE (ret_type); | ||
| 46 | + rtx extend; | ||
| 47 | + if (TYPE_UNSIGNED (ret_type)) | ||
| 48 | + extend = gen_rtx_ZERO_EXTEND (SImode, | ||
| 49 | + gen_rtx_REG (ret_mode, R0_REGNUM)); | ||
| 50 | + else | ||
| 51 | + extend = gen_rtx_SIGN_EXTEND (SImode, | ||
| 52 | + gen_rtx_REG (ret_mode, R0_REGNUM)); | ||
| 53 | + emit_insn_after (gen_rtx_SET (gen_rtx_REG (SImode, R0_REGNUM), | ||
| 54 | + extend), insn); | ||
| 55 | + | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + | ||
| 59 | if (TARGET_HAVE_FPCXT_CMSE) | ||
| 60 | { | ||
| 61 | rtx_insn *last, *pop_insn, *after = insn; | ||
| 62 | @@ -23652,6 +23676,51 @@ arm_expand_prologue (void) | ||
| 63 | |||
| 64 | ip_rtx = gen_rtx_REG (SImode, IP_REGNUM); | ||
| 65 | |||
| 66 | + /* The AAPCS requires the callee to widen integral types narrower | ||
| 67 | + than 32 bits to the full width of the register; but when handling | ||
| 68 | + calls to non-secure space, we cannot trust the callee to have | ||
| 69 | + correctly done so. So forcibly re-widen the result here. */ | ||
| 70 | + if (IS_CMSE_ENTRY (func_type)) | ||
| 71 | + { | ||
| 72 | + function_args_iterator args_iter; | ||
| 73 | + CUMULATIVE_ARGS args_so_far_v; | ||
| 74 | + cumulative_args_t args_so_far; | ||
| 75 | + bool first_param = true; | ||
| 76 | + tree arg_type; | ||
| 77 | + tree fndecl = current_function_decl; | ||
| 78 | + tree fntype = TREE_TYPE (fndecl); | ||
| 79 | + arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl); | ||
| 80 | + args_so_far = pack_cumulative_args (&args_so_far_v); | ||
| 81 | + FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter) | ||
| 82 | + { | ||
| 83 | + rtx arg_rtx; | ||
| 84 | + | ||
| 85 | + if (VOID_TYPE_P (arg_type)) | ||
| 86 | + break; | ||
| 87 | + | ||
| 88 | + function_arg_info arg (arg_type, /*named=*/true); | ||
| 89 | + if (!first_param) | ||
| 90 | + /* We should advance after processing the argument and pass | ||
| 91 | + the argument we're advancing past. */ | ||
| 92 | + arm_function_arg_advance (args_so_far, arg); | ||
| 93 | + first_param = false; | ||
| 94 | + arg_rtx = arm_function_arg (args_so_far, arg); | ||
| 95 | + gcc_assert (REG_P (arg_rtx)); | ||
| 96 | + if ((TREE_CODE (arg_type) == INTEGER_TYPE | ||
| 97 | + || TREE_CODE (arg_type) == ENUMERAL_TYPE | ||
| 98 | + || TREE_CODE (arg_type) == BOOLEAN_TYPE) | ||
| 99 | + && known_lt (GET_MODE_SIZE (GET_MODE (arg_rtx)), 4)) | ||
| 100 | + { | ||
| 101 | + if (TYPE_UNSIGNED (arg_type)) | ||
| 102 | + emit_set_insn (gen_rtx_REG (SImode, REGNO (arg_rtx)), | ||
| 103 | + gen_rtx_ZERO_EXTEND (SImode, arg_rtx)); | ||
| 104 | + else | ||
| 105 | + emit_set_insn (gen_rtx_REG (SImode, REGNO (arg_rtx)), | ||
| 106 | + gen_rtx_SIGN_EXTEND (SImode, arg_rtx)); | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | if (IS_STACKALIGN (func_type)) | ||
| 112 | { | ||
| 113 | rtx r0, r1; | ||
| 114 | diff --git a/gcc/testsuite/gcc.target/arm/cmse/extend-param.c b/gcc/testsuite/gcc.target/arm/cmse/extend-param.c | ||
| 115 | new file mode 100644 | ||
| 116 | index 0000000000000000000000000000000000000000..01fac7862385f871f3ecc246ede95eea180be025 | ||
| 117 | --- /dev/null | ||
| 118 | +++ b/gcc/testsuite/gcc.target/arm/cmse/extend-param.c | ||
| 119 | @@ -0,0 +1,96 @@ | ||
| 120 | +/* { dg-do compile } */ | ||
| 121 | +/* { dg-options "-mcmse" } */ | ||
| 122 | +/* { dg-final { check-function-bodies "**" "" "" } } */ | ||
| 123 | + | ||
| 124 | +#include <arm_cmse.h> | ||
| 125 | +#include <stdbool.h> | ||
| 126 | + | ||
| 127 | +#define ARRAY_SIZE (256) | ||
| 128 | +char array[ARRAY_SIZE]; | ||
| 129 | + | ||
| 130 | +enum offset | ||
| 131 | +{ | ||
| 132 | + zero = 0, | ||
| 133 | + one = 1, | ||
| 134 | + two = 2 | ||
| 135 | +}; | ||
| 136 | + | ||
| 137 | +/* | ||
| 138 | +**__acle_se_unsignSecureFunc: | ||
| 139 | +** ... | ||
| 140 | +** uxtb r0, r0 | ||
| 141 | +** ... | ||
| 142 | +*/ | ||
| 143 | +__attribute__((cmse_nonsecure_entry)) char unsignSecureFunc (unsigned char index) { | ||
| 144 | + if (index >= ARRAY_SIZE) | ||
| 145 | + return 0; | ||
| 146 | + return array[index]; | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +/* | ||
| 150 | +**__acle_se_signSecureFunc: | ||
| 151 | +** ... | ||
| 152 | +** sxtb r0, r0 | ||
| 153 | +** ... | ||
| 154 | +*/ | ||
| 155 | +__attribute__((cmse_nonsecure_entry)) char signSecureFunc (signed char index) { | ||
| 156 | + if (index >= ARRAY_SIZE) | ||
| 157 | + return 0; | ||
| 158 | + return array[index]; | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +/* | ||
| 162 | +**__acle_se_shortUnsignSecureFunc: | ||
| 163 | +** ... | ||
| 164 | +** uxth r0, r0 | ||
| 165 | +** ... | ||
| 166 | +*/ | ||
| 167 | +__attribute__((cmse_nonsecure_entry)) char shortUnsignSecureFunc (unsigned short index) { | ||
| 168 | + if (index >= ARRAY_SIZE) | ||
| 169 | + return 0; | ||
| 170 | + return array[index]; | ||
| 171 | +} | ||
| 172 | + | ||
| 173 | +/* | ||
| 174 | +**__acle_se_shortSignSecureFunc: | ||
| 175 | +** ... | ||
| 176 | +** sxth r0, r0 | ||
| 177 | +** ... | ||
| 178 | +*/ | ||
| 179 | +__attribute__((cmse_nonsecure_entry)) char shortSignSecureFunc (signed short index) { | ||
| 180 | + if (index >= ARRAY_SIZE) | ||
| 181 | + return 0; | ||
| 182 | + return array[index]; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +/* | ||
| 186 | +**__acle_se_enumSecureFunc: | ||
| 187 | +** ... | ||
| 188 | +** uxtb r0, r0 | ||
| 189 | +** ... | ||
| 190 | +*/ | ||
| 191 | +__attribute__((cmse_nonsecure_entry)) char enumSecureFunc (enum offset index) { | ||
| 192 | + | ||
| 193 | + // Compiler may optimize away bounds check as value is an unsigned char. | ||
| 194 | + | ||
| 195 | + // According to AAPCS caller will zero extend to ensure value is < 256. | ||
| 196 | + | ||
| 197 | + if (index >= ARRAY_SIZE) | ||
| 198 | + return 0; | ||
| 199 | + return array[index]; | ||
| 200 | + | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +/* | ||
| 204 | +**__acle_se_boolSecureFunc: | ||
| 205 | +** ... | ||
| 206 | +** uxtb r0, r0 | ||
| 207 | +** ... | ||
| 208 | +*/ | ||
| 209 | +__attribute__((cmse_nonsecure_entry)) char boolSecureFunc (bool index) { | ||
| 210 | + | ||
| 211 | + if (index >= ARRAY_SIZE) | ||
| 212 | + return 0; | ||
| 213 | + return array[index]; | ||
| 214 | + | ||
| 215 | +} | ||
| 216 | \ No newline at end of file | ||
| 217 | diff --git a/gcc/testsuite/gcc.target/arm/cmse/extend-return.c b/gcc/testsuite/gcc.target/arm/cmse/extend-return.c | ||
| 218 | new file mode 100644 | ||
| 219 | index 0000000000000000000000000000000000000000..cf731ed33df7e6dc101320c1970016f01b14c59a | ||
| 220 | --- /dev/null | ||
| 221 | +++ b/gcc/testsuite/gcc.target/arm/cmse/extend-return.c | ||
| 222 | @@ -0,0 +1,92 @@ | ||
| 223 | +/* { dg-do compile } */ | ||
| 224 | +/* { dg-options "-mcmse" } */ | ||
| 225 | +/* { dg-final { check-function-bodies "**" "" "" } } */ | ||
| 226 | + | ||
| 227 | +#include <arm_cmse.h> | ||
| 228 | +#include <stdbool.h> | ||
| 229 | + | ||
| 230 | +enum offset | ||
| 231 | +{ | ||
| 232 | + zero = 0, | ||
| 233 | + one = 1, | ||
| 234 | + two = 2 | ||
| 235 | +}; | ||
| 236 | + | ||
| 237 | +typedef unsigned char __attribute__ ((cmse_nonsecure_call)) ns_unsign_foo_t (void); | ||
| 238 | +typedef signed char __attribute__ ((cmse_nonsecure_call)) ns_sign_foo_t (void); | ||
| 239 | +typedef unsigned short __attribute__ ((cmse_nonsecure_call)) ns_short_unsign_foo_t (void); | ||
| 240 | +typedef signed short __attribute__ ((cmse_nonsecure_call)) ns_short_sign_foo_t (void); | ||
| 241 | +typedef enum offset __attribute__ ((cmse_nonsecure_call)) ns_enum_foo_t (void); | ||
| 242 | +typedef bool __attribute__ ((cmse_nonsecure_call)) ns_bool_foo_t (void); | ||
| 243 | + | ||
| 244 | +/* | ||
| 245 | +**unsignNonsecure0: | ||
| 246 | +** ... | ||
| 247 | +** bl __gnu_cmse_nonsecure_call | ||
| 248 | +** uxtb r0, r0 | ||
| 249 | +** ... | ||
| 250 | +*/ | ||
| 251 | +unsigned char unsignNonsecure0 (ns_unsign_foo_t * ns_foo_p) | ||
| 252 | +{ | ||
| 253 | + return ns_foo_p (); | ||
| 254 | +} | ||
| 255 | + | ||
| 256 | +/* | ||
| 257 | +**signNonsecure0: | ||
| 258 | +** ... | ||
| 259 | +** bl __gnu_cmse_nonsecure_call | ||
| 260 | +** sxtb r0, r0 | ||
| 261 | +** ... | ||
| 262 | +*/ | ||
| 263 | +signed char signNonsecure0 (ns_sign_foo_t * ns_foo_p) | ||
| 264 | +{ | ||
| 265 | + return ns_foo_p (); | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +/* | ||
| 269 | +**shortUnsignNonsecure0: | ||
| 270 | +** ... | ||
| 271 | +** bl __gnu_cmse_nonsecure_call | ||
| 272 | +** uxth r0, r0 | ||
| 273 | +** ... | ||
| 274 | +*/ | ||
| 275 | +unsigned short shortUnsignNonsecure0 (ns_short_unsign_foo_t * ns_foo_p) | ||
| 276 | +{ | ||
| 277 | + return ns_foo_p (); | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +/* | ||
| 281 | +**shortSignNonsecure0: | ||
| 282 | +** ... | ||
| 283 | +** bl __gnu_cmse_nonsecure_call | ||
| 284 | +** sxth r0, r0 | ||
| 285 | +** ... | ||
| 286 | +*/ | ||
| 287 | +signed short shortSignNonsecure0 (ns_short_sign_foo_t * ns_foo_p) | ||
| 288 | +{ | ||
| 289 | + return ns_foo_p (); | ||
| 290 | +} | ||
| 291 | + | ||
| 292 | +/* | ||
| 293 | +**enumNonsecure0: | ||
| 294 | +** ... | ||
| 295 | +** bl __gnu_cmse_nonsecure_call | ||
| 296 | +** uxtb r0, r0 | ||
| 297 | +** ... | ||
| 298 | +*/ | ||
| 299 | +unsigned char __attribute__((noipa)) enumNonsecure0 (ns_enum_foo_t * ns_foo_p) | ||
| 300 | +{ | ||
| 301 | + return ns_foo_p (); | ||
| 302 | +} | ||
| 303 | + | ||
| 304 | +/* | ||
| 305 | +**boolNonsecure0: | ||
| 306 | +** ... | ||
| 307 | +** bl __gnu_cmse_nonsecure_call | ||
| 308 | +** uxtb r0, r0 | ||
| 309 | +** ... | ||
| 310 | +*/ | ||
| 311 | +unsigned char boolNonsecure0 (ns_bool_foo_t * ns_foo_p) | ||
| 312 | +{ | ||
| 313 | + return ns_foo_p (); | ||
| 314 | +} | ||
| 315 | \ No newline at end of file | ||
