ANDROID: GKI: Protect exports of protected GKI modules

Implement support for protecting the exported symbols of
protected GKI modules.

Only signed GKI modules are permitted to export symbols
listed in the android/abi_gki_protected_exports file.
Attempting to export these symbols from an unsigned module
will result in the module failing to load, with a
'Permission denied' error message.

Bug: 232430739
Test: TH
Change-Id: I3e8b330938e116bb2e022d356ac0d55108a84a01
Signed-off-by: Ramji Jiyani <ramjiyani@google.com>
This commit is contained in:
Ramji Jiyani
2022-12-16 06:32:13 +00:00
committed by Treehugger Robot
parent 5e28b84896
commit fd1e768866
6 changed files with 54 additions and 13 deletions

View File

View File

@@ -160,12 +160,18 @@ $(obj)/kheaders_data.tar.xz: FORCE
clean-files := kheaders_data.tar.xz kheaders.md5 clean-files := kheaders_data.tar.xz kheaders.md5
# #
# ANDROID: GKI: Generate headerfile required for gki_module.o # ANDROID: GKI: Generate headerfiles required for gki_module.o
# #
# Dependencies on generated files need to be listed explicitly # Dependencies on generated files need to be listed explicitly
$(obj)/gki_module.o: $(obj)/gki_module_unprotected.h $(obj)/gki_module.o: $(obj)/gki_module_protected_exports.h \
$(obj)/gki_module_unprotected.h
$(obj)/gki_module_unprotected.h: $(srctree)/scripts/gen_gki_modules_headers.sh \ $(obj)/gki_module_unprotected.h: $(srctree)/scripts/gen_gki_modules_headers.sh \
$(if $(wildcard ${OUT_DIR}/abi_symbollist.raw), ${OUT_DIR}/abi_symbollist.raw) $(if $(wildcard ${OUT_DIR}/abi_symbollist.raw), ${OUT_DIR}/abi_symbollist.raw)
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/gen_gki_modules_headers.sh $@ \ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/gen_gki_modules_headers.sh $@ \
"$(srctree)" "$(srctree)"
$(obj)/gki_module_protected_exports.h: $(srctree)/android/abi_gki_protected_exports \
$(srctree)/scripts/gen_gki_modules_headers.sh
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/gen_gki_modules_headers.sh $@ \
"$(srctree)"

View File

@@ -13,14 +13,29 @@
/* /*
* Build time generated header files * Build time generated header files
* *
* gki_module_protected_exports.h -- Symbols protected from _export_ by unsigned modules
* gki_module_unprotected.h -- Symbols allowed to _access_ by unsigned modules * gki_module_unprotected.h -- Symbols allowed to _access_ by unsigned modules
*/ */
#include "gki_module_protected_exports.h"
#include "gki_module_unprotected.h" #include "gki_module_unprotected.h"
#define MAX_STRCMP_LEN (max(MAX_UNPROTECTED_NAME_LEN, MAX_PROTECTED_EXPORTS_NAME_LEN))
/* bsearch() comparision callback */ /* bsearch() comparision callback */
static int cmp_name(const void *sym, const void *protected_sym) static int cmp_name(const void *sym, const void *protected_sym)
{ {
return strncmp(sym, protected_sym, MAX_UNPROTECTED_NAME_LEN); return strncmp(sym, protected_sym, MAX_STRCMP_LEN);
}
/**
* gki_is_module_protected_export - Is a symbol exported from a protected GKI module?
*
* @name: Symbol being checked against exported symbols from protected GKI modules
*/
bool gki_is_module_protected_export(const char *name)
{
return bsearch(name, gki_protected_exports_symbols, NR_PROTECTED_EXPORTS_SYMBOLS,
MAX_PROTECTED_EXPORTS_NAME_LEN, cmp_name) != NULL;
} }
/** /**
@@ -30,8 +45,8 @@ static int cmp_name(const void *sym, const void *protected_sym)
*/ */
bool gki_is_module_unprotected_symbol(const char *name) bool gki_is_module_unprotected_symbol(const char *name)
{ {
if (NO_OF_UNPROTECTED_SYMBOLS) { if (NR_UNPROTECTED_SYMBOLS) {
return bsearch(name, gki_unprotected_symbols, NO_OF_UNPROTECTED_SYMBOLS, return bsearch(name, gki_unprotected_symbols, NR_UNPROTECTED_SYMBOLS,
MAX_UNPROTECTED_NAME_LEN, cmp_name) != NULL; MAX_UNPROTECTED_NAME_LEN, cmp_name) != NULL;
} else { } else {
/* /*

View File

@@ -32,9 +32,14 @@ extern int mod_verify_sig(const void *mod, struct load_info *info);
#ifdef CONFIG_MODULE_SIG_PROTECT #ifdef CONFIG_MODULE_SIG_PROTECT
extern bool gki_is_module_unprotected_symbol(const char *name); extern bool gki_is_module_unprotected_symbol(const char *name);
extern bool gki_is_module_protected_export(const char *name);
#else #else
static inline bool gki_is_module_unprotected_symbol(const char *name) static inline bool gki_is_module_unprotected_symbol(const char *name)
{ {
return 1; return 1;
} }
static inline bool gki_is_module_protected_export(const char *name)
{
return 0;
}
#endif /* CONFIG_MODULE_SIG_PROTECT */ #endif /* CONFIG_MODULE_SIG_PROTECT */

View File

@@ -2282,6 +2282,14 @@ static int verify_exported_symbols(struct module *mod)
.name = kernel_symbol_name(s), .name = kernel_symbol_name(s),
.gplok = true, .gplok = true,
}; };
if (!mod->sig_ok && gki_is_module_protected_export(
kernel_symbol_name(s))) {
pr_err("%s: exports protected symbol %s\n",
mod->name, kernel_symbol_name(s));
return -EACCES;
}
if (find_symbol(&fsa)) { if (find_symbol(&fsa)) {
pr_err("%s: exports duplicate symbol %s" pr_err("%s: exports duplicate symbol %s"
" (owned by %s)\n", " (owned by %s)\n",

View File

@@ -49,11 +49,11 @@ generate_header() {
# Find Maximum symbol name length if valid symbol_file exist # Find Maximum symbol name length if valid symbol_file exist
if [ -s "${symbol_file}" ]; then if [ -s "${symbol_file}" ]; then
# Skip 1st line (symbol header), Trim white spaces & +1 for null termination # Trim white spaces & +1 for null termination
local max_name_len=$(awk ' local max_name_len=$(awk '
{ {
$1=$1; $1=$1;
if ( length > L && NR > 1) { if ( length > L ) {
L=length L=length
} }
} END { print ++L }' "${symbol_file}") } END { print ++L }' "${symbol_file}")
@@ -67,11 +67,11 @@ generate_header() {
/* /*
* DO NOT EDIT * DO NOT EDIT
* *
* Build generated header file with unprotected symbols/exports * Build generated header file with ${symbol_type}
*/ */
#define NO_OF_$(printf ${symbol_type} | tr [:lower:] [:upper:])_SYMBOLS \\ #define NR_$(printf ${symbol_type} | tr [:lower:] [:upper:])_SYMBOLS \\
$(printf '\t')(sizeof(gki_${symbol_type}_symbols) / sizeof(gki_${symbol_type}_symbols[0])) $(printf '\t')(ARRAY_SIZE(gki_${symbol_type}_symbols))
#define MAX_$(printf ${symbol_type} | tr [:lower:] [:upper:])_NAME_LEN (${max_name_len}) #define MAX_$(printf ${symbol_type} | tr [:lower:] [:upper:])_NAME_LEN (${max_name_len})
static const char gki_${symbol_type}_symbols[][MAX_$(printf ${symbol_type} | static const char gki_${symbol_type}_symbols[][MAX_$(printf ${symbol_type} |
@@ -87,8 +87,15 @@ generate_header() {
echo "};" >> "${header_file}" echo "};" >> "${header_file}"
} }
if [ "$(basename "${TARGET}")" = "gki_module_unprotected.h" ]; then
# Sorted list of vendor symbols # Sorted list of vendor symbols
GKI_VENDOR_SYMBOLS="${OUT_DIR}/abi_symbollist.raw" GKI_VENDOR_SYMBOLS="${OUT_DIR}/abi_symbollist.raw"
generate_header "${TARGET}" "${GKI_VENDOR_SYMBOLS}" "unprotected" generate_header "${TARGET}" "${GKI_VENDOR_SYMBOLS}" "unprotected"
else
# Sorted list of exported symbols
GKI_EXPORTED_SYMBOLS="${SRCTREE}/android/abi_gki_protected_exports"
generate_header "${TARGET}" "${GKI_EXPORTED_SYMBOLS}" "protected_exports"
fi