Skip to content

Commit

Permalink
x86/cfi: Boot time selection of CFI scheme
Browse files Browse the repository at this point in the history
Add the "cfi=" boot parameter to allow people to select a CFI scheme
at boot time. Mostly useful for development / debugging.

Requested-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20221027092842.699804264@infradead.org
  • Loading branch information
Peter Zijlstra committed Nov 1, 2022
1 parent 931ab63 commit 082c4c8
Showing 1 changed file with 81 additions and 18 deletions.
99 changes: 81 additions & 18 deletions arch/x86/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,47 @@ void __init_or_module noinline apply_ibt_endbr(s32 *start, s32 *end) { }
#endif /* CONFIG_X86_KERNEL_IBT */

#ifdef CONFIG_FINEIBT

enum cfi_mode {
CFI_DEFAULT,
CFI_OFF,
CFI_KCFI,
CFI_FINEIBT,
};

static enum cfi_mode cfi_mode __ro_after_init = CFI_DEFAULT;

static __init int cfi_parse_cmdline(char *str)
{
if (!str)
return -EINVAL;

while (str) {
char *next = strchr(str, ',');
if (next) {
*next = 0;
next++;
}

if (!strcmp(str, "auto")) {
cfi_mode = CFI_DEFAULT;
} else if (!strcmp(str, "off")) {
cfi_mode = CFI_OFF;
} else if (!strcmp(str, "kcfi")) {
cfi_mode = CFI_KCFI;
} else if (!strcmp(str, "fineibt")) {
cfi_mode = CFI_FINEIBT;
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}

str = next;
}

return 0;
}
early_param("cfi", cfi_parse_cmdline);

/*
* kCFI FineIBT
*
Expand Down Expand Up @@ -868,30 +909,52 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
"FineIBT preamble wrong size: %ld", fineibt_preamble_size))
return;

if (!HAS_KERNEL_IBT || !cpu_feature_enabled(X86_FEATURE_IBT))
if (cfi_mode == CFI_DEFAULT) {
cfi_mode = CFI_KCFI;
if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
cfi_mode = CFI_FINEIBT;
}

switch (cfi_mode) {
case CFI_OFF:
ret = cfi_disable_callers(start_retpoline, end_retpoline);
if (ret)
goto err;

if (builtin)
pr_info("Disabling CFI\n");
return;

/*
* Rewrite the callers to not use the __cfi_ stubs, such that we might
* rewrite them. This disables all CFI. If this succeeds but any of the
* later stages fails, we're without CFI.
*/
ret = cfi_disable_callers(start_retpoline, end_retpoline);
if (ret)
goto err;
case CFI_KCFI:
if (builtin)
pr_info("Using kCFI\n");
return;

ret = cfi_rewrite_preamble(start_cfi, end_cfi);
if (ret)
goto err;
case CFI_FINEIBT:
/*
* Rewrite the callers to not use the __cfi_ stubs, such that we might
* rewrite them. This disables all CFI. If this succeeds but any of the
* later stages fails, we're without CFI.
*/
ret = cfi_disable_callers(start_retpoline, end_retpoline);
if (ret)
goto err;

ret = cfi_rewrite_preamble(start_cfi, end_cfi);
if (ret)
goto err;

ret = cfi_rewrite_callers(start_retpoline, end_retpoline);
if (ret)
goto err;
ret = cfi_rewrite_callers(start_retpoline, end_retpoline);
if (ret)
goto err;

if (builtin)
pr_info("Using FineIBT CFI\n");
if (builtin)
pr_info("Using FineIBT CFI\n");
return;

return;
default:
break;
}

err:
pr_err("Something went horribly wrong trying to rewrite the CFI implementation.\n");
Expand Down

0 comments on commit 082c4c8

Please sign in to comment.