Skip to content

Commit 5adde3d

Browse files
committed
riscv/cfi: Support locking/disabling CFI and move OS depedent code
1 parent f3f2beb commit 5adde3d

File tree

2 files changed

+94
-11
lines changed

2 files changed

+94
-11
lines changed

sysdeps/riscv/dl-cfi.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ struct dl_cfi_info
5757
static void
5858
dl_check_legacy_object (struct link_map *m, struct dl_cfi_info *info)
5959
{
60-
/* Iterate through the dependencies and disable if needed here */
60+
/* Iterate through the dependencies and record legacy objects */
6161
struct link_map *l = NULL;
6262
unsigned int i;
6363
i = m->l_searchlist.r_nlist;
@@ -86,7 +86,11 @@ dl_check_legacy_object (struct link_map *m, struct dl_cfi_info *info)
8686
| ~(GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
8787
| GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS));
8888

89-
/* Bookkeeping legacy objects */
89+
/* Bookkeeping first found mismatch object for both lp/ss.
90+
These information would only be used by dlopen check for now.
91+
A dependency with a feature on will be record as legacy if the task
92+
did not enable the feature, however it is safe because the following
93+
check will only be performed if the task has the feature on. */
9094
#ifdef __riscv_landing_pad
9195
if ((info->feature_1_legacy & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) == 0
9296
&& ((info->enable_feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
@@ -208,8 +212,8 @@ dl_cfi_check_dlopen (struct link_map *m, struct dl_cfi_info *info)
208212
_dl_signal_error (0, m->l_initfini[legacy_obj]->l_name, "dlopen", msg);
209213

210214
if (disable_feature_1 != 0)
211-
// FIXME: Disable CFI here
212-
int res = -1;
215+
{
216+
int res = dl_cfi_disable_cfi (disable_feature_1);
213217
if (res)
214218
{
215219
msg = N_("can't disable CFI feature");
@@ -223,14 +227,29 @@ dl_cfi_check_dlopen (struct link_map *m, struct dl_cfi_info *info)
223227
attribute_hidden void
224228
_dl_cfi_setup_features (unsigned int feature_1)
225229
{
226-
/* Since prctl could fail to enable some features
227-
use prctl to get enabled features again and sync it back. */
230+
/* Enable features. Shadow stack is enabled earlier as it should
231+
* be enabled in a function that never returns. */
232+
#ifdef __riscv_landing_pad
233+
dl_cfi_enable_lp (feature_1);
234+
#endif /* __riscv_landing_pad */
235+
236+
/* Since we could failed to enable some features,
237+
get enabled features from system again and sync it back. */
238+
int status = dl_cfi_get_cfi_status ();
239+
GL(dl_riscv_feature_1) = status | (GL(dl_riscv_feature_1) &
240+
~(GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
241+
| GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED));
242+
243+
/* Lock features if set to always_on */
228244
#ifdef __riscv_landing_pad
229-
if (feature_1 & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
230-
INTERNAL_SYSCALL_CALL (prctl, PR_SET_INDIR_BR_LP_STATUS,
231-
PR_INDIR_BR_LP_ENABLE, 0, 0, 0);
245+
if (GL(dl_riscv_feature_control).lp == cfi_always_on)
246+
dl_cfi_lock_cfi (GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED);
232247
#endif /* __riscv_landing_pad */
233-
/* FIXME: Read enabled features from kernel and re-sync */
248+
#ifdef __riscv_shadow_stack
249+
if (GL(dl_riscv_feature_control).ss == cfi_always_on)
250+
dl_cfi_lock_cfi (GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
251+
#endif /* __riscv_shadow_stack */
252+
/* FIXME: Should we terminate if failed to lock under always on mode? */
234253
}
235254

236255
/* Enable CFI for l and its dependencies. */
@@ -287,7 +306,6 @@ _dl_cfi_check (struct link_map *l, const char *program)
287306
info.feature_1_legacy_ss = 0;
288307
#endif
289308

290-
info.feature_1_enabled = GL(dl_riscv_feature_1);
291309
info.feature_1_legacy = 0;
292310

293311
#ifdef SHARED

sysdeps/unix/sysv/linux/riscv/dl-cfi.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,68 @@
4848
jal _dl_cfi_setup_features \n\
4949
\n\
5050
"
51+
52+
static __always_inline int
53+
dl_cfi_disable_cfi (unsigned int feature) {
54+
int res = 0;
55+
#ifdef __riscv_landing_pad
56+
if (feature & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
57+
{
58+
res = prctl (PR_SET_INDIR_BR_LP_STATUS, 0, 0, 0, 0);
59+
if (res)
60+
return res;
61+
}
62+
#endif /* __riscv_landing_pad */
63+
#ifdef __riscv_shadow_stack
64+
if (feature & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
65+
{
66+
res |= prctl (PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
67+
if (res)
68+
return res;
69+
}
70+
#endif /* __riscv_shadow_stack */
71+
return 0;
72+
}
73+
74+
static __always_inline int
75+
dl_cfi_lock_cfi (unsigned int feature)
76+
{
77+
int res = 0;
78+
#ifdef __riscv_landing_pad
79+
if (feature & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
80+
res |= prctl (PR_LOCK_INDIR_BR_LP_STATUS, 0, 0, 0, 0);
81+
#endif /* __riscv_landing_pad */
82+
#ifdef __riscv_shadow_stack
83+
if (feature & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
84+
res |= prctl (PR_LOCK_SHADOW_STACK_STATUS, 0, 0, 0, 0);
85+
#endif /* __riscv_shadow_stack */
86+
return res;
87+
}
88+
89+
static __always_inline int
90+
dl_cfi_get_cfi_status (void) {
91+
int status = 0;
92+
int buf = 0;
93+
int ret = 0;
94+
#ifdef __riscv_landing_pad
95+
ret = prctl (PR_GET_INDIR_BR_LP_STATUS, &buf, 0, 0, 0);
96+
if (!ret && buf)
97+
status |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
98+
#endif /* __riscv_landing_pad */
99+
#ifdef __riscv_shadow_stack
100+
ret = prctl (PR_GET_SHADOW_STACK_STATUS, &buf, 0, 0, 0);
101+
if (!ret && buf)
102+
status |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
103+
#endif /* __riscv_shadow_stack */
104+
return status;
105+
}
106+
107+
#ifdef __riscv_landing_pad
108+
static __always_inline int
109+
dl_cfi_enable_lp (unsigned int feature) {
110+
if (!(feature & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED))
111+
return -1;
112+
return INTERNAL_SYSCALL_CALL (prctl, PR_SET_INDIR_BR_LP_STATUS,
113+
PR_INDIR_BR_LP_ENABLE, 0, 0, 0);
114+
}
115+
#endif /* __riscv_landing_pad */

0 commit comments

Comments
 (0)