ANDROID: fips140 - add option for debugging the integrity check
There now have been two times where I've had to debug the fips140 integrity check failing due to a new type of runtime code patching. Debugging such issues requires dumping the text and rodata actually used for the integrity check and comparing them with the originals. Add a kconfig option to make this easier. Similar to CRYPTO_FIPS140_MOD_EVAL_TESTING, the production build won't use this. Bug: 188620248 Change-Id: I392de466ff31f999d65997dbc610e23e9eeca49d Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
parent
fd3551098b
commit
1616e03be1
@ -79,6 +79,33 @@ config CRYPTO_FIPS140_MOD_EVAL_TESTING
|
||||
errors and support for a userspace interface to some of the module's
|
||||
services. This option should not be enabled in production builds.
|
||||
|
||||
config CRYPTO_FIPS140_MOD_DEBUG_INTEGRITY_CHECK
|
||||
bool "Debug the integrity check in FIPS 140 module"
|
||||
depends on CRYPTO_FIPS140_MOD
|
||||
help
|
||||
This option makes the FIPS 140 module provide debugfs files containing
|
||||
the text and rodata that were used for the integrity check, i.e. the
|
||||
runtime text and rodata with relocations and code patches unapplied.
|
||||
This option also makes the module load even if the integrity check
|
||||
fails so that these files can be used to debug the failure. (A
|
||||
possible failure mode is that the kernel has added a new type of code
|
||||
patching and the module needs to be updated to disable or unapply it.)
|
||||
|
||||
This option must not be enabled in production builds.
|
||||
|
||||
Example commands for debugging an integrity check failure:
|
||||
|
||||
adb root
|
||||
adb shell mount debugfs -t debugfs /sys/kernel/debug
|
||||
adb shell cp /sys/kernel/debug/fips140/{text,rodata} /data/local/tmp/
|
||||
adb pull /data/local/tmp/text text.checked
|
||||
adb pull /data/local/tmp/rodata rodata.checked
|
||||
llvm-objcopy -O binary --only-section=.text fips140.ko text.orig
|
||||
llvm-objcopy -O binary --only-section=.rodata fips140.ko rodata.orig
|
||||
for f in {text,rodata}.{orig,checked}; do xxd -g1 $f > $f.xxd; done
|
||||
vimdiff text.{orig,checked}.xxd
|
||||
vimdiff rodata.{orig,checked}.xxd
|
||||
|
||||
config CRYPTO_ALGAPI
|
||||
tristate
|
||||
select CRYPTO_ALGAPI2
|
||||
|
@ -23,6 +23,7 @@
|
||||
#undef __DISABLE_EXPORTS
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/aes.h>
|
||||
@ -357,6 +358,67 @@ static void __init unapply_rodata_relocations(void *section, int section_size,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CRYPTO_FIPS140_MOD_DEBUG_INTEGRITY_CHECK
|
||||
static struct {
|
||||
const void *text;
|
||||
int textsize;
|
||||
const void *rodata;
|
||||
int rodatasize;
|
||||
} saved_integrity_check_info;
|
||||
|
||||
static ssize_t fips140_text_read(struct file *file, char __user *to,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return simple_read_from_buffer(to, count, ppos,
|
||||
saved_integrity_check_info.text,
|
||||
saved_integrity_check_info.textsize);
|
||||
}
|
||||
|
||||
static ssize_t fips140_rodata_read(struct file *file, char __user *to,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return simple_read_from_buffer(to, count, ppos,
|
||||
saved_integrity_check_info.rodata,
|
||||
saved_integrity_check_info.rodatasize);
|
||||
}
|
||||
|
||||
static const struct file_operations fips140_text_fops = {
|
||||
.read = fips140_text_read,
|
||||
};
|
||||
|
||||
static const struct file_operations fips140_rodata_fops = {
|
||||
.read = fips140_rodata_read,
|
||||
};
|
||||
|
||||
static void fips140_init_integrity_debug_files(const void *text, int textsize,
|
||||
const void *rodata,
|
||||
int rodatasize)
|
||||
{
|
||||
struct dentry *dir;
|
||||
|
||||
dir = debugfs_create_dir("fips140", NULL);
|
||||
|
||||
saved_integrity_check_info.text = kmemdup(text, textsize, GFP_KERNEL);
|
||||
saved_integrity_check_info.textsize = textsize;
|
||||
if (saved_integrity_check_info.text)
|
||||
debugfs_create_file("text", 0400, dir, NULL,
|
||||
&fips140_text_fops);
|
||||
|
||||
saved_integrity_check_info.rodata = kmemdup(rodata, rodatasize,
|
||||
GFP_KERNEL);
|
||||
saved_integrity_check_info.rodatasize = rodatasize;
|
||||
if (saved_integrity_check_info.rodata)
|
||||
debugfs_create_file("rodata", 0400, dir, NULL,
|
||||
&fips140_rodata_fops);
|
||||
}
|
||||
#else /* CONFIG_CRYPTO_FIPS140_MOD_DEBUG_INTEGRITY_CHECK */
|
||||
static void fips140_init_integrity_debug_files(const void *text, int textsize,
|
||||
const void *rodata,
|
||||
int rodatasize)
|
||||
{
|
||||
}
|
||||
#endif /* !CONFIG_CRYPTO_FIPS140_MOD_DEBUG_INTEGRITY_CHECK */
|
||||
|
||||
extern struct {
|
||||
u32 offset;
|
||||
u32 count;
|
||||
@ -398,6 +460,9 @@ static bool __init check_fips140_module_hmac(void)
|
||||
offset_to_ptr(&fips140_rela_rodata.offset),
|
||||
fips140_rela_rodata.count);
|
||||
|
||||
fips140_init_integrity_debug_files(textcopy, textsize,
|
||||
rodatacopy, rodatasize);
|
||||
|
||||
fips140_inject_integrity_failure(textcopy);
|
||||
|
||||
tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
|
||||
@ -538,10 +603,14 @@ fips140_init(void)
|
||||
*/
|
||||
|
||||
if (!check_fips140_module_hmac()) {
|
||||
if (!IS_ENABLED(CONFIG_CRYPTO_FIPS140_MOD_DEBUG_INTEGRITY_CHECK)) {
|
||||
pr_crit("integrity check failed -- giving up!\n");
|
||||
goto panic;
|
||||
}
|
||||
pr_crit("ignoring integrity check failure due to debug mode\n");
|
||||
} else {
|
||||
pr_info("integrity check passed\n");
|
||||
}
|
||||
|
||||
complete_all(&fips140_tests_done);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user