Skip to content

Commit f141243

Browse files
ricbal02stephanosio
authored andcommitted
arm: Zero/Sign extends for CMSE security
Co-Authored by: Andre Simoes Dias Vieira <Andre.SimoesDiasVieira@arm.com> This patch makes the following changes: 1) When calling a secure function from non-secure code then any arguments smaller than 32-bits that are passed in registers are zero- or sign-extended. 2) After a non-secure function returns into secure code then any return value smaller than 32-bits that is passed in a register is zero- or sign-extended. This patch addresses the following CVE-2024-0151. gcc/ChangeLog: PR target/114837 * config/arm/arm.cc (cmse_nonsecure_call_inline_register_clear): Add zero/sign extend. (arm_expand_prologue): Add zero/sign extend. gcc/testsuite/ChangeLog: * gcc.target/arm/cmse/extend-param.c: New test. * gcc.target/arm/cmse/extend-return.c: New test. (cherry picked from commit ad45086) (cherry picked from commit 441e194) Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
1 parent 504d8c3 commit f141243

File tree

3 files changed

+257
-0
lines changed

3 files changed

+257
-0
lines changed

gcc/config/arm/arm.cc

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18971,6 +18971,30 @@ cmse_nonsecure_call_inline_register_clear (void)
1897118971
end_sequence ();
1897218972
emit_insn_before (seq, insn);
1897318973

18974+
/* The AAPCS requires the callee to widen integral types narrower
18975+
than 32 bits to the full width of the register; but when handling
18976+
calls to non-secure space, we cannot trust the callee to have
18977+
correctly done so. So forcibly re-widen the result here. */
18978+
tree ret_type = TREE_TYPE (fntype);
18979+
if ((TREE_CODE (ret_type) == INTEGER_TYPE
18980+
|| TREE_CODE (ret_type) == ENUMERAL_TYPE
18981+
|| TREE_CODE (ret_type) == BOOLEAN_TYPE)
18982+
&& known_lt (GET_MODE_SIZE (TYPE_MODE (ret_type)), 4))
18983+
{
18984+
machine_mode ret_mode = TYPE_MODE (ret_type);
18985+
rtx extend;
18986+
if (TYPE_UNSIGNED (ret_type))
18987+
extend = gen_rtx_ZERO_EXTEND (SImode,
18988+
gen_rtx_REG (ret_mode, R0_REGNUM));
18989+
else
18990+
extend = gen_rtx_SIGN_EXTEND (SImode,
18991+
gen_rtx_REG (ret_mode, R0_REGNUM));
18992+
emit_insn_after (gen_rtx_SET (gen_rtx_REG (SImode, R0_REGNUM),
18993+
extend), insn);
18994+
18995+
}
18996+
18997+
1897418998
if (TARGET_HAVE_FPCXT_CMSE)
1897518999
{
1897619000
rtx_insn *last, *pop_insn, *after = insn;
@@ -23379,6 +23403,51 @@ arm_expand_prologue (void)
2337923403

2338023404
ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
2338123405

23406+
/* The AAPCS requires the callee to widen integral types narrower
23407+
than 32 bits to the full width of the register; but when handling
23408+
calls to non-secure space, we cannot trust the callee to have
23409+
correctly done so. So forcibly re-widen the result here. */
23410+
if (IS_CMSE_ENTRY (func_type))
23411+
{
23412+
function_args_iterator args_iter;
23413+
CUMULATIVE_ARGS args_so_far_v;
23414+
cumulative_args_t args_so_far;
23415+
bool first_param = true;
23416+
tree arg_type;
23417+
tree fndecl = current_function_decl;
23418+
tree fntype = TREE_TYPE (fndecl);
23419+
arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
23420+
args_so_far = pack_cumulative_args (&args_so_far_v);
23421+
FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
23422+
{
23423+
rtx arg_rtx;
23424+
23425+
if (VOID_TYPE_P (arg_type))
23426+
break;
23427+
23428+
function_arg_info arg (arg_type, /*named=*/true);
23429+
if (!first_param)
23430+
/* We should advance after processing the argument and pass
23431+
the argument we're advancing past. */
23432+
arm_function_arg_advance (args_so_far, arg);
23433+
first_param = false;
23434+
arg_rtx = arm_function_arg (args_so_far, arg);
23435+
gcc_assert (REG_P (arg_rtx));
23436+
if ((TREE_CODE (arg_type) == INTEGER_TYPE
23437+
|| TREE_CODE (arg_type) == ENUMERAL_TYPE
23438+
|| TREE_CODE (arg_type) == BOOLEAN_TYPE)
23439+
&& known_lt (GET_MODE_SIZE (GET_MODE (arg_rtx)), 4))
23440+
{
23441+
if (TYPE_UNSIGNED (arg_type))
23442+
emit_set_insn (gen_rtx_REG (SImode, REGNO (arg_rtx)),
23443+
gen_rtx_ZERO_EXTEND (SImode, arg_rtx));
23444+
else
23445+
emit_set_insn (gen_rtx_REG (SImode, REGNO (arg_rtx)),
23446+
gen_rtx_SIGN_EXTEND (SImode, arg_rtx));
23447+
}
23448+
}
23449+
}
23450+
2338223451
if (IS_STACKALIGN (func_type))
2338323452
{
2338423453
rtx r0, r1;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-mcmse" } */
3+
/* { dg-final { check-function-bodies "**" "" "" } } */
4+
5+
#include <arm_cmse.h>
6+
#include <stdbool.h>
7+
8+
#define ARRAY_SIZE (256)
9+
char array[ARRAY_SIZE];
10+
11+
enum offset
12+
{
13+
zero = 0,
14+
one = 1,
15+
two = 2
16+
};
17+
18+
/*
19+
**__acle_se_unsignSecureFunc:
20+
** ...
21+
** uxtb r0, r0
22+
** ...
23+
*/
24+
__attribute__((cmse_nonsecure_entry)) char unsignSecureFunc (unsigned char index) {
25+
if (index >= ARRAY_SIZE)
26+
return 0;
27+
return array[index];
28+
}
29+
30+
/*
31+
**__acle_se_signSecureFunc:
32+
** ...
33+
** sxtb r0, r0
34+
** ...
35+
*/
36+
__attribute__((cmse_nonsecure_entry)) char signSecureFunc (signed char index) {
37+
if (index >= ARRAY_SIZE)
38+
return 0;
39+
return array[index];
40+
}
41+
42+
/*
43+
**__acle_se_shortUnsignSecureFunc:
44+
** ...
45+
** uxth r0, r0
46+
** ...
47+
*/
48+
__attribute__((cmse_nonsecure_entry)) char shortUnsignSecureFunc (unsigned short index) {
49+
if (index >= ARRAY_SIZE)
50+
return 0;
51+
return array[index];
52+
}
53+
54+
/*
55+
**__acle_se_shortSignSecureFunc:
56+
** ...
57+
** sxth r0, r0
58+
** ...
59+
*/
60+
__attribute__((cmse_nonsecure_entry)) char shortSignSecureFunc (signed short index) {
61+
if (index >= ARRAY_SIZE)
62+
return 0;
63+
return array[index];
64+
}
65+
66+
/*
67+
**__acle_se_enumSecureFunc:
68+
** ...
69+
** uxtb r0, r0
70+
** ...
71+
*/
72+
__attribute__((cmse_nonsecure_entry)) char enumSecureFunc (enum offset index) {
73+
74+
// Compiler may optimize away bounds check as value is an unsigned char.
75+
76+
// According to AAPCS caller will zero extend to ensure value is < 256.
77+
78+
if (index >= ARRAY_SIZE)
79+
return 0;
80+
return array[index];
81+
82+
}
83+
84+
/*
85+
**__acle_se_boolSecureFunc:
86+
** ...
87+
** uxtb r0, r0
88+
** ...
89+
*/
90+
__attribute__((cmse_nonsecure_entry)) char boolSecureFunc (bool index) {
91+
92+
if (index >= ARRAY_SIZE)
93+
return 0;
94+
return array[index];
95+
96+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/* { dg-do compile } */
2+
/* { dg-options "-mcmse" } */
3+
/* { dg-final { check-function-bodies "**" "" "" } } */
4+
5+
#include <arm_cmse.h>
6+
#include <stdbool.h>
7+
8+
enum offset
9+
{
10+
zero = 0,
11+
one = 1,
12+
two = 2
13+
};
14+
15+
typedef unsigned char __attribute__ ((cmse_nonsecure_call)) ns_unsign_foo_t (void);
16+
typedef signed char __attribute__ ((cmse_nonsecure_call)) ns_sign_foo_t (void);
17+
typedef unsigned short __attribute__ ((cmse_nonsecure_call)) ns_short_unsign_foo_t (void);
18+
typedef signed short __attribute__ ((cmse_nonsecure_call)) ns_short_sign_foo_t (void);
19+
typedef enum offset __attribute__ ((cmse_nonsecure_call)) ns_enum_foo_t (void);
20+
typedef bool __attribute__ ((cmse_nonsecure_call)) ns_bool_foo_t (void);
21+
22+
/*
23+
**unsignNonsecure0:
24+
** ...
25+
** bl __gnu_cmse_nonsecure_call
26+
** uxtb r0, r0
27+
** ...
28+
*/
29+
unsigned char unsignNonsecure0 (ns_unsign_foo_t * ns_foo_p)
30+
{
31+
return ns_foo_p ();
32+
}
33+
34+
/*
35+
**signNonsecure0:
36+
** ...
37+
** bl __gnu_cmse_nonsecure_call
38+
** sxtb r0, r0
39+
** ...
40+
*/
41+
signed char signNonsecure0 (ns_sign_foo_t * ns_foo_p)
42+
{
43+
return ns_foo_p ();
44+
}
45+
46+
/*
47+
**shortUnsignNonsecure0:
48+
** ...
49+
** bl __gnu_cmse_nonsecure_call
50+
** uxth r0, r0
51+
** ...
52+
*/
53+
unsigned short shortUnsignNonsecure0 (ns_short_unsign_foo_t * ns_foo_p)
54+
{
55+
return ns_foo_p ();
56+
}
57+
58+
/*
59+
**shortSignNonsecure0:
60+
** ...
61+
** bl __gnu_cmse_nonsecure_call
62+
** sxth r0, r0
63+
** ...
64+
*/
65+
signed short shortSignNonsecure0 (ns_short_sign_foo_t * ns_foo_p)
66+
{
67+
return ns_foo_p ();
68+
}
69+
70+
/*
71+
**enumNonsecure0:
72+
** ...
73+
** bl __gnu_cmse_nonsecure_call
74+
** uxtb r0, r0
75+
** ...
76+
*/
77+
unsigned char __attribute__((noipa)) enumNonsecure0 (ns_enum_foo_t * ns_foo_p)
78+
{
79+
return ns_foo_p ();
80+
}
81+
82+
/*
83+
**boolNonsecure0:
84+
** ...
85+
** bl __gnu_cmse_nonsecure_call
86+
** uxtb r0, r0
87+
** ...
88+
*/
89+
unsigned char boolNonsecure0 (ns_bool_foo_t * ns_foo_p)
90+
{
91+
return ns_foo_p ();
92+
}

0 commit comments

Comments
 (0)