/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "hdf_security.h" #include #include #include #include #include #include #include #include #include #include "hcs_tree_if.h" #include "hdf_base.h" #include "hdf_log.h" #include "hdf_sec.h" #include "pal_if.h" #include "securec.h" #define HDF_LOG_TAG hdf_security #define HDF_SECURE_PATH "/dev/hdf_secure" #define HDF_SEC_PERM_ELEM_NAME "permission" #define HDF_SEC_HOST_NAME "hostName" #define MAX_RANDOM_BYTE_LEN 8 #define RAND_OPS_SUCCESS 1 #define MAX_SEED_LEN 64 #define HDF_TRANSFORM_STEP 2 #define HDF_SECURE_INVALID_PERM 0 #define HDF_SECURE_SET_ALL_ID 0 #define HDF_SECURE_SET_CUR_ID 1 #define HDF_SECURE_DEL_CUR_ID 2 #define BITS_PER_LONG 64 #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) const static char *g_hdfSecStrArray[PAL_MAX_TYPE] = { [PAL_I2C_TYPE] = "i2c", [PAL_SPI_TYPE] = "spi", [PAL_GPIO_TYPE] = "gpio", [PAL_PINCTRL_TYPE] = "pinctl", [PAL_CLOCK_TYPE] = "clock", [PAL_REGULATOR_TYPE] = "regulator", [PAL_MIPI_TYPE] = "mipi", [PAL_UART_TYPE] = "uart", [PAL_SDIO_TYPE] = "sdio", [PAL_MDIO_TYPE] = "mdio", [PAL_APB_TYPE] = "apb", [PAL_PCIE_TYPE] = "pcie", [PAL_PCM_TYPE] = "pcm", [PAL_I2S_TYPE] = "i2s", [PAL_PWM_TYPE] = "pwm", [PAL_DMA_TYPE] = "dma", [PAL_EFUSE_TYPE] = "efuse", [PAL_FLASH_TYPE] = "flash", [PAL_EMMC_TYPE] = "emmc", [PAL_RTC_TYPE] = "rtc", [PAL_ADC_TYPE] = "adc", [PAL_WDT_TYPE] = "wdt", [PAL_I3C_TYPE] = "i3c", }; static Map g_indexMap; Map *HdfSecGetHashMap() { static Map hdfHashMap = { 0 }; if (hdfHashMap.nodeSize == 0) { HDF_LOGI("Init hdfHashMap"); MapInit(&hdfHashMap); } return &hdfHashMap; } static void InitStrToIndexMap(void) { MapInit(&g_indexMap); for (int i = 0; i < PAL_MAX_TYPE; ++i) { MapSet(&g_indexMap, g_hdfSecStrArray[i], &i, sizeof(int *)); } } static void HdfSetBit(uint32_t nr, volatile uint64_t *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); *p |= mask; } static int32_t HdfGetRandom(int numBytes, uint8_t *random) { if (RAND_bytes(random, numBytes) != RAND_OPS_SUCCESS) { HDF_LOGE("%{public}s: RAND_bytes failed", __FUNCTION__); return HDF_FAILURE; } return HDF_SUCCESS; } static void HdfCalculatePerms(const char *permStr, volatile uint64_t *perms) { uint32_t *result = NULL; result = (uint32_t *)MapGet(&g_indexMap, permStr); if (result == NULL) { HDF_LOGE("%{public}s: %{public}s is not exist in map", __FUNCTION__, permStr); return; } HdfSetBit(*result, perms); } static int32_t HdfSecCheckParameters(const char *id) { if (id == NULL) { HDF_LOGE("HdfSecCheckParameters failed, id is null"); return HDF_FAILURE; } uint32_t len = (uint32_t)strlen(id); if (len >= (ID_MAX_SIZE - 1)) { HDF_LOGE("HdfSecCheckParameters failed, id length is %{public}u", len); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t HdfUpdateSecurityId(const char *id, uint64_t perms, int32_t isSetCurrentSecId) { if (HdfSecCheckParameters(id) != HDF_SUCCESS) { HDF_LOGE("%{public}s check id failed", __FUNCTION__); return HDF_FAILURE; } struct SecInfo secInfo = { .secId = { 0 }, .secMap = { 0 } }; int32_t ret = strncpy_s(secInfo.secId, ID_MAX_SIZE, id, ID_MAX_SIZE - 1); if (ret != EOK) { HDF_LOGE("%{public}s strncpy_s id failed", __FUNCTION__); return HDF_FAILURE; } secInfo.secMap[0] = perms; char path[PATH_MAX + 1] = { 0 }; if (realpath(HDF_SECURE_PATH, path) == NULL) { HDF_LOGE("file %{public}s is invalid", HDF_SECURE_PATH); return HDF_FAILURE; } int32_t fd = open(path, O_WRONLY); if (fd < 0) { HDF_LOGE("open %{public}s failed, errno is %{public}d", HDF_SECURE_PATH, errno); return HDF_FAILURE; } if (isSetCurrentSecId == 0) { ret = ioctl(fd, HDF_SECURE_SET_INFO, &secInfo); } else if (isSetCurrentSecId == 1) { ret = ioctl(fd, HDF_SECURE_SET_CURRENT_ID, &secInfo); } else { ret = ioctl(fd, HDF_SECURE_DELETE_INFO, &secInfo); } close(fd); fd = -1; if (ret != 0) { HDF_LOGE("%{public}s ioctl error, ret is %{public}d", __FUNCTION__, ret); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t HdfRegisterSecurityId(const char *id, const uint64_t perm) { return HdfUpdateSecurityId(id, perm, HDF_SECURE_SET_ALL_ID); } int32_t HdfRegisterAllDevSecId(const struct DeviceResourceNode *hostRoot) { if (hostRoot == NULL) { HDF_LOGE("device_node linked list completed"); return HDF_FAILURE; } uint64_t random = 0; int32_t ret = HdfGetRandom(MAX_RANDOM_BYTE_LEN, (uint8_t *)&random); if (ret != HDF_SUCCESS) { HDF_LOGE("%{public}s HdfGetRandom failed", __FUNCTION__); return HDF_FAILURE; } InitStrToIndexMap(); struct DeviceResourceNode *driverRoot = hostRoot->child; const char *permStr = NULL; volatile uint64_t perms = HDF_SECURE_INVALID_PERM; while (driverRoot != NULL) { const struct DeviceResourceNode *deviceRoot = driverRoot->child; while (deviceRoot != NULL) { int32_t permNums = HcsGetElemNum(deviceRoot, HDF_SEC_PERM_ELEM_NAME); HDF_LOGD("name is %{public}s, permNums is %{public}d", deviceRoot->name, permNums); for (int i = 0; i < permNums; ++i) { HcsGetStringArrayElem(deviceRoot, HDF_SEC_PERM_ELEM_NAME, i, &permStr, NULL); HdfCalculatePerms(permStr, &perms); } deviceRoot = deviceRoot->sibling; } driverRoot = driverRoot->sibling; } if (perms != HDF_SECURE_INVALID_PERM) { const char *hostName = NULL; HcsGetString(hostRoot, HDF_SEC_HOST_NAME, &hostName, NULL); ret = HdfRegisterSecurityId(hostName, perms); if (ret != HDF_SUCCESS) { HDF_LOGE("HdfCreateSecurityId failed for %{public}s", hostRoot->name); } perms = HDF_SECURE_INVALID_PERM; } return HDF_SUCCESS; } int32_t HdfSetCurrentHostSecurity(const char *hostName, int32_t procId) { return HdfUpdateSecurityId(hostName, (uint64_t)procId, HDF_SECURE_SET_CUR_ID); } void HdfDelSecurity(const char *hostName) { if (hostName == NULL) { return; } int32_t ret = HdfUpdateSecurityId(hostName, 0, HDF_SECURE_DEL_CUR_ID); if (ret != HDF_SUCCESS) { HDF_LOGE("%{public}s delete %{public}s security failed", __func__, hostName); } }