// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2020 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtk_selinux_warning.h" #ifdef CONFIG_MTK_AEE_FEATURE #include #endif #define PRINT_BUF_LEN 100 #define MOD "SELINUX" #define SCONTEXT_FILTER #define AV_FILTER /* #define ENABLE_CURRENT_NE_CORE_DUMP */ #ifdef ENABLE_CURRENT_NE_CORE_DUMP #include static atomic_t ne_warning_count; #define POLLING_NE_PROCESS_COUNT 5 #endif static const char *aee_filter_list[AEE_FILTER_NUM] = { "u:r:bootanim:s0", "u:r:system_server:s0", "u:r:zygote:s0", "u:r:surfaceflinger:s0", "u:r:netd:s0", "u:r:servicemanager:s0", "u:r:hwservicemanager:s0", "u:r:hal_graphics_composer_default:s0", "u:r:hal_graphics_allocator_default:s0", "u:r:mtk_hal_audio:s0", "u:r:priv_app:s0", }; #ifdef NEVER static const char * const aee_filter_unused[] = { "u:r:bluetooth:s0", "u:r:binderservicedomain:s0", "u:r:dex2oat:s0", "u:r:dhcp:s0", "u:r:dnsmasq:s0", "u:r:dumpstate:s0", "u:r:gpsd:s0", "u:r:healthd:s0", "u:r:hci_attach:s0", "u:r:hostapd:s0", "u:r:inputflinger:s0", "u:r:isolated_app:s0", "u:r:keystore:s0", "u:r:lmkd:s0", "u:r:mdnsd:s0", "u:r:logd:s0", "u:r:mtp:s0", "u:r:nfc:s0", "u:r:ppp:s0", "u:r:racoon:s0", "u:r:recovery:s0", "u:r:rild:s0", "u:r:runas:s0", "u:r:sdcardd:s0", "u:r:shared_relro:s0", "u:r:tee:s0", "u:r:uncrypt:s0", "u:r:watchdogd:s0", "u:r:wpa:s0", "u:r:ueventd:s0", "u:r:vold:s0", "u:r:vdc:s0", }; #endif #define AEE_AV_FILTER_NUM 5 static const char *aee_av_filter_list[AEE_AV_FILTER_NUM] = { "map", "ioctl" }; #define SKIP_PATTERN_NUM 5 static const char *skip_pattern[SKIP_PATTERN_NUM] = { "scontext=u:r:untrusted_app" }; static int mtk_check_filter(char *scontext); static int mtk_get_scontext(char *data, char *buf); static char *mtk_get_process(char *in); static int mtk_check_filter(char *scontext) { int i = 0; /*check whether scontext in filter list */ for (i = 0; i < AEE_FILTER_NUM && aee_filter_list[i] != NULL; i++) { if (strcmp(scontext, aee_filter_list[i]) == 0) return i; } return -1; } static bool mtk_check_skip_pattern(char *data) { int i = 0; /* check whether the log contains specific pattern*/ for (i = 0; i < SKIP_PATTERN_NUM && skip_pattern[i] != NULL; i++) { if (strstr(data, skip_pattern[i]) != NULL) return true; } return false; } #define AV_LEN 30 static void mtk_check_av(char *data) { char *start = NULL; char *end = NULL; char av_buf[AV_LEN] = { '\0' }; char scontext[AEE_FILTER_LEN] = { '\0' }; char printbuf[PRINT_BUF_LEN] = { '\0' }; char *pname = scontext; char *iter; int i; if (!mtk_get_scontext(data, scontext)) return; pname = mtk_get_process(scontext); if (pname == 0) return; start = strstr(data, "denied { "); end = strstr(data, "}"); if (start == NULL || end == NULL || end < start) return; start = start+10; iter = start; while (iter < end) { if (*iter == ' ' && iter-start > 0 && iter-start < AV_LEN) { strncpy(av_buf, start, iter-start); for (i = 0; i < AEE_AV_FILTER_NUM && aee_av_filter_list[i] != NULL; ++i) { if (strcmp(av_buf, aee_av_filter_list[i]) == 0) { if (mtk_check_skip_pattern(data)) return; memset(printbuf, '\0', PRINT_BUF_LEN); snprintf(printbuf, PRINT_BUF_LEN-1, "[%s][WARNING]\nCR_DISPATCH_PROCESSNAME:%s\n", MOD, pname); #ifdef CONFIG_MTK_AEE_FEATURE aee_kernel_warning_api( __FILE__, __LINE__, DB_OPT_DEFAULT | DB_OPT_NATIVE_BACKTRACE, printbuf, data); #endif } } start = iter+1; } iter++; } } static int mtk_get_scontext(char *data, char *buf) { char *t1; char *t2; int diff = 0; t1 = strstr(data, "scontext="); if (t1 == NULL) return 0; t1 += 9; t2 = strchr(t1, ' '); if (t2 == NULL) return 0; diff = t2 - t1; if (diff >= AEE_FILTER_LEN) return 0; strncpy(buf, t1, diff); return 1; } static char *mtk_get_process(char *in) { char *out = in; char *tmp; int i; /*Omit two ':' */ for (i = 0; i < 2; i++) { out = strchr(out, ':'); if (out == NULL) return 0; out = out + 1; } tmp = strchr(out, ':'); if (tmp == NULL) return 0; *tmp = '\0'; return out; } void mtk_audit_hook(char *data) { #ifdef SCONTEXT_FILTER char scontext[AEE_FILTER_LEN] = { '\0' }; char *pname = scontext; int ret = 0; /*get scontext from avc warning */ ret = mtk_get_scontext(data, scontext); if (!ret) return; /*check scontext is in warning list */ ret = mtk_check_filter(scontext); if (ret >= 0) { pr_debug("[%s], In AEE Warning List scontext: %s\n", MOD, scontext); if (!IS_ENABLED(CONFIG_MTK_AEE_FEATURE)) return; pname = mtk_get_process(scontext); if (pname != 0) { char printbuf[PRINT_BUF_LEN] = { '\0' }; #ifdef ENABLE_CURRENT_NE_CORE_DUMP int count = 0; struct task_struct *task; pid_t pid = current->pid; /* pid need dump */ pid_t tgid = current->tgid; char *selinux_ne = get_env("selinux_ne"); if (selinux_ne != NULL) { long ne_option; int err = kstrtol(selinux_ne, 10, &ne_option); if (err || (ne_option != 1)) { pr_debug("[%s] ne_opt:%ld, err:%d\n", MOD, ne_option, err); return; } } else { pr_debug("[%s] ne option is null\n", MOD); return; } if (atomic_read(&ne_warning_count) >= 1) return; send_sig(SIGSEGV, current, 0); atomic_inc(&ne_warning_count); #endif snprintf(printbuf, PRINT_BUF_LEN-1, "[%s][WARNING]\nCR_DISPATCH_PROCESSNAME:%s\n", MOD, pname); #ifdef CONFIG_MTK_AEE_FEATURE aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_DEFAULT | DB_OPT_NATIVE_BACKTRACE, printbuf, data); #endif #ifdef ENABLE_CURRENT_NE_CORE_DUMP /* poll NE process and wait for its exitence */ while (count < POLLING_NE_PROCESS_COUNT) { rcu_read_lock(); task = find_task_by_vpid(pid); rcu_read_unlock(); if (task == NULL) { pr_debug("[%s] pid: %d exist.\n", MOD, pid); break; /* pid exit, safe to return */ } /* wait two more seconds */ pr_debug("[%s] pid: %d, tgid: %d, wait(%ds)\n", MOD, pid, tgid, count); msleep(2000); count++; } #endif } } #endif #ifdef AV_FILTER mtk_check_av(data); #endif } EXPORT_SYMBOL(mtk_audit_hook);