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
#
# 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
$(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 \
$(if $(wildcard ${OUT_DIR}/abi_symbollist.raw), ${OUT_DIR}/abi_symbollist.raw)
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/gen_gki_modules_headers.sh $@ \
"$(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
*
* gki_module_protected_exports.h -- Symbols protected from _export_ 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"
#define MAX_STRCMP_LEN (max(MAX_UNPROTECTED_NAME_LEN, MAX_PROTECTED_EXPORTS_NAME_LEN))
/* bsearch() comparision callback */
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)
{
if (NO_OF_UNPROTECTED_SYMBOLS) {
return bsearch(name, gki_unprotected_symbols, NO_OF_UNPROTECTED_SYMBOLS,
if (NR_UNPROTECTED_SYMBOLS) {
return bsearch(name, gki_unprotected_symbols, NR_UNPROTECTED_SYMBOLS,
MAX_UNPROTECTED_NAME_LEN, cmp_name) != NULL;
} else {
/*

View File

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

View File

@@ -2282,6 +2282,14 @@ static int verify_exported_symbols(struct module *mod)
.name = kernel_symbol_name(s),
.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)) {
pr_err("%s: exports duplicate symbol %s"
" (owned by %s)\n",

View File

@@ -49,11 +49,11 @@ generate_header() {
# Find Maximum symbol name length if valid symbol_file exist
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 '
{
$1=$1;
if ( length > L && NR > 1) {
if ( length > L ) {
L=length
}
} END { print ++L }' "${symbol_file}")
@@ -67,11 +67,11 @@ generate_header() {
/*
* 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 \\
$(printf '\t')(sizeof(gki_${symbol_type}_symbols) / sizeof(gki_${symbol_type}_symbols[0]))
#define NR_$(printf ${symbol_type} | tr [:lower:] [:upper:])_SYMBOLS \\
$(printf '\t')(ARRAY_SIZE(gki_${symbol_type}_symbols))
#define MAX_$(printf ${symbol_type} | tr [:lower:] [:upper:])_NAME_LEN (${max_name_len})
static const char gki_${symbol_type}_symbols[][MAX_$(printf ${symbol_type} |
@@ -87,8 +87,15 @@ generate_header() {
echo "};" >> "${header_file}"
}
# Sorted list of vendor symbols
GKI_VENDOR_SYMBOLS="${OUT_DIR}/abi_symbollist.raw"
if [ "$(basename "${TARGET}")" = "gki_module_unprotected.h" ]; then
# Sorted list of vendor symbols
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