Commit 082c4c81 authored by Peter Zijlstra's avatar Peter Zijlstra
Browse files

x86/cfi: Boot time selection of CFI scheme



Add the "cfi=" boot parameter to allow people to select a CFI scheme
at boot time. Mostly useful for development / debugging.

Requested-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20221027092842.699804264@infradead.org
parent 931ab636
Loading
Loading
Loading
Loading
+81 −18
Original line number Diff line number Diff line
@@ -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
 *
@@ -868,9 +909,28 @@ 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;

	case CFI_KCFI:
		if (builtin)
			pr_info("Using kCFI\n");
		return;

	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
@@ -890,9 +950,12 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,

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

		return;

	default:
		break;
	}

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