From f8bd6cf70dec3961c8b15b987866af33be2ce82b Mon Sep 17 00:00:00 2001 From: Ramji Jiyani Date: Thu, 25 Nov 2021 00:57:24 +0000 Subject: [PATCH] ANDROID: GKI: Add module load time protected symbol lookup Add CONFIG_MODULE_SIG_PROTECT to enable lookup for the protected symbols and exports from the build time generated list of symbols and exports. Module loading behavior will change as follows: - Allows Android GKI Modules signed using MODULE_SIG_ALL during build. - Allows other modules to load if they don't violate the access to Android GKI protected symbols and do not export the symbols already exported by the Android GKI modules. Loading will fail and return -EACCES (Permission denied) if symbol access contidions are not met. Bug: 200082547 Test: Treehugger Signed-off-by: Ramji Jiyani Change-Id: Iedb99d8434db82a9c7f18ffd363d84f4b2316c5b (cherry picked from commit 9ab6a242258a9ac17506b74c6ed7332703d536f4) --- android/abi_gki_modules_exports | 1 + android/abi_gki_modules_protected | 1 + arch/arm64/configs/gki_defconfig | 2 ++ arch/x86/configs/gki_defconfig | 2 ++ init/Kconfig | 14 +++++++++ kernel/Makefile | 17 +++++++++++ kernel/gki_module.c | 50 +++++++++++++++++++++++++++++++ kernel/module-internal.h | 14 +++++++++ kernel/module.c | 19 +++++++++++- 9 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 android/abi_gki_modules_exports create mode 100644 android/abi_gki_modules_protected create mode 100644 kernel/gki_module.c diff --git a/android/abi_gki_modules_exports b/android/abi_gki_modules_exports new file mode 100644 index 000000000000..88b5a4b3adce --- /dev/null +++ b/android/abi_gki_modules_exports @@ -0,0 +1 @@ +[abi_symbol_list] diff --git a/android/abi_gki_modules_protected b/android/abi_gki_modules_protected new file mode 100644 index 000000000000..88b5a4b3adce --- /dev/null +++ b/android/abi_gki_modules_protected @@ -0,0 +1 @@ +[abi_symbol_list] diff --git a/arch/arm64/configs/gki_defconfig b/arch/arm64/configs/gki_defconfig index e7747575bc73..0ad89920991a 100644 --- a/arch/arm64/configs/gki_defconfig +++ b/arch/arm64/configs/gki_defconfig @@ -93,6 +93,8 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SCMVERSION=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_PROTECT=y CONFIG_BLK_INLINE_ENCRYPTION=y CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_IOSCHED_BFQ=y diff --git a/arch/x86/configs/gki_defconfig b/arch/x86/configs/gki_defconfig index 8960e8665c1d..2c4057eb20f4 100644 --- a/arch/x86/configs/gki_defconfig +++ b/arch/x86/configs/gki_defconfig @@ -75,6 +75,8 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SCMVERSION=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_PROTECT=y CONFIG_BLK_INLINE_ENCRYPTION=y CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_IOSCHED_BFQ=y diff --git a/init/Kconfig b/init/Kconfig index 21bfdcd7f8d4..b3c1abcf93f3 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2196,6 +2196,20 @@ config MODULE_SIG_FORCE Reject unsigned modules or signed modules for which we don't have a key. Without this, such modules will simply taint the kernel. +config MODULE_SIG_PROTECT + bool "Android GKI module protection" + depends on MODULE_SIG && !MODULE_SIG_FORCE + select MODULE_SIG_ALL + help + Enables Android GKI symbol and export protection support. + + This modifies the behavior of the MODULE_SIG_FORCE as follows: + - Allows Android GKI Modules signed using MODULE_SIG_ALL during build. + - Allows other modules to load if they don't violate the access to + Android GKI protected symbols and do not export the symbols already + exported by the Android GKI modules. Loading will fail and return + -EACCES (Permission denied) if symbol access contidions are not met. + config MODULE_SIG_ALL bool "Automatically sign all modules" default y diff --git a/kernel/Makefile b/kernel/Makefile index 4df609be42d0..c60ddb19af1d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SIG) += module_signing.o obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o +obj-$(CONFIG_MODULE_SIG_PROTECT) += gki_module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_CRASH_CORE) += crash_core.o @@ -159,3 +160,19 @@ $(obj)/kheaders_data.tar.xz: FORCE $(call cmd,genikh) clean-files := kheaders_data.tar.xz kheaders.md5 + +# +# ANDROID: GKI: Generate headerfiles required for gki_module.o +# +# Dependencies on generated files need to be listed explicitly +$(obj)/gki_module.o: $(obj)/gki_module_protected.h $(obj)/gki_module_exported.h + +$(obj)/gki_module_protected.h: $(srctree)/android/abi_gki_modules_protected \ + $(srctree)/scripts/gen_gki_modules_headers.sh + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/gen_gki_modules_headers.sh $@ \ + "$(srctree)" + +$(obj)/gki_module_exported.h: $(srctree)/android/abi_gki_modules_exports \ + $(srctree)/scripts/gen_gki_modules_headers.sh + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/gen_gki_modules_headers.sh $@ \ + "$(srctree)" diff --git a/kernel/gki_module.c b/kernel/gki_module.c new file mode 100644 index 000000000000..24651dfc34f8 --- /dev/null +++ b/kernel/gki_module.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2021 Google LLC + * Author: ramjiyani@google.com (Ramji Jiyani) + */ + +#include +#include +#include +#include +#include + +/* + * Build time generated header files + * + * gki_module_exported.h -- Symbols protected from _export_ by unsigned modules + * gki_module_protected.h -- Symbols protected from _access_ by unsigned modules + */ +#include "gki_module_protected.h" +#include "gki_module_exported.h" + +#define MAX_STRCMP_LEN (max(MAX_PROTECTED_NAME_LEN, MAX_EXPORTED_NAME_LEN)) + +/* bsearch() comparision callback */ +static int cmp_name(const void *sym, const void *protected_sym) +{ + return strncmp(sym, protected_sym, MAX_STRCMP_LEN); +} + +/** + * gki_is_module_protected_symbol - Is a symbol protected from unsigned module? + * + * @name: Symbol being checked against protection from unsigned module + */ +bool gki_is_module_protected_symbol(const char *name) +{ + return bsearch(name, gki_protected_symbols, NO_OF_PROTECTED_SYMBOLS, + MAX_PROTECTED_NAME_LEN, cmp_name) != NULL; +} + +/** + * gki_is_module_exported_symbol - Is a symbol exported from a GKI module? + * + * @name: Symbol being checked against exported symbols from GKI modules + */ +bool gki_is_module_exported_symbol(const char *name) +{ + return bsearch(name, gki_exported_symbols, NO_OF_EXPORTED_SYMBOLS, + MAX_EXPORTED_NAME_LEN, cmp_name) != NULL; +} diff --git a/kernel/module-internal.h b/kernel/module-internal.h index 33783abc377b..9b040512536e 100644 --- a/kernel/module-internal.h +++ b/kernel/module-internal.h @@ -29,3 +29,17 @@ struct load_info { }; extern int mod_verify_sig(const void *mod, struct load_info *info); + +#ifdef CONFIG_MODULE_SIG_PROTECT +extern bool gki_is_module_exported_symbol(const char *name); +extern bool gki_is_module_protected_symbol(const char *name); +#else +static inline bool gki_is_module_exported_symbol(const char *name) +{ + return 0; +} +static inline bool gki_is_module_protected_symbol(const char *name) +{ + return 0; +} +#endif /* CONFIG_MODULE_SIG_PROTECT */ diff --git a/kernel/module.c b/kernel/module.c index 2708f02372ba..780feb512610 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -271,7 +271,7 @@ static void module_assert_mutex_or_preempt(void) #endif } -#ifdef CONFIG_MODULE_SIG +#if defined(CONFIG_MODULE_SIG) && !defined(CONFIG_MODULE_SIG_PROTECT) static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE); module_param(sig_enforce, bool_enable_only, 0644); @@ -2267,6 +2267,14 @@ static int verify_exported_symbols(struct module *mod) .name = kernel_symbol_name(s), .gplok = true, }; + + if (!mod->sig_ok && gki_is_module_exported_symbol( + kernel_symbol_name(s))) { + pr_err("%s: exporting protected symbol(%s)\n", + mod->name, kernel_symbol_name(s)); + return -EACCES; + } + if (find_symbol(&fsa)) { pr_err("%s: exports duplicate symbol %s" " (owned by %s)\n", @@ -2334,6 +2342,13 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) break; case SHN_UNDEF: + if (!mod->sig_ok && + gki_is_module_protected_symbol(name)) { + pr_err("%s: is not an Android GKI signed module. It can not access protected symbol: %s\n", + mod->name, name); + return -EACCES; + } + ksym = resolve_symbol_wait(mod, info, name); /* Ok if resolved. */ if (ksym && !IS_ERR(ksym)) { @@ -4023,6 +4038,8 @@ static int load_module(struct load_info *info, const char __user *uargs, "kernel\n", mod->name); add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK); } +#else + mod->sig_ok = 0; #endif /* To avoid stressing percpu allocator, do this once we're unique. */