未验证 提交 3b6a39a2 编写于 作者: O openharmony_ci 提交者: Gitee

!1720 init 增加 hvb 特性 挑单monthly

Merge pull request !1720 from 万欣/cherry-pick-1674197234
......@@ -38,7 +38,8 @@
"hiviewdfx",
"access_token",
"common",
"dsoftbus"
"dsoftbus",
"hvb"
],
"third_party": [
"cJSON",
......
......@@ -31,6 +31,26 @@ ohos_static_library("libfsmanager_static") {
"//base/startup/init/services/include",
"//base/startup/init/services/param/include",
]
if (defined(global_parts_info.startup_hvb)) {
sources += [
"dm_verity/dm_verity.c",
"libfs_dm/fs_dm.c",
"libfs_hvb/fs_hvb.c",
"libfs_hvb/hvb_ops.c",
]
include_dirs += [
"//base/startup/init/interfaces/innerkits/fs_manager/libfs_dm/include",
"//base/startup/init/interfaces/innerkits/fs_manager/libfs_hvb/include",
"//base/startup/init/interfaces/innerkits/fs_manager/dm_verity/include",
"//base/startup/hvb/libhvb/include",
"//base/startup/init/ueventd/include",
]
defines = [ "SUPPORT_HVB" ]
public_deps = [ "//base/startup/hvb/libhvb:libhvb_static" ]
}
public_configs = [ ":libfsmanager_exported_configs" ]
part_name = "init"
subsystem_name = "startup"
......
/*
* Copyright (c) 2022-2023 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 "dm_verity.h"
#include "fs_hvb.h"
#include "securec.h"
#include "beget_ext.h"
#include <stdbool.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#define HVB_VERIFIEDBOOT_STATE_STR_MAX_LEN 32
#define HVB_CMDLINE_VERIFIEDBOOT_STATE "ohos.boot.verifiedbootstate"
#define HVB_FORCE_ENABLE_STR_MAX_LEN 16
#define HVB_CMDLINE_HVB_FORCE_ENABLE "ohos.boot.oem_swtype"
#define DM_VERITY_RETURN_ERR_IF_NULL(__ptr) \
do { \
if ((__ptr) == NULL) { \
BEGET_LOGE("error, %s is NULL\n", #__ptr); \
return -1; \
} \
} while (0)
static bool HvbDmVerityIsEnable()
{
int rc;
char forceEnable[HVB_FORCE_ENABLE_STR_MAX_LEN] = {0};
char verifiedBootState[HVB_VERIFIEDBOOT_STATE_STR_MAX_LEN] = {0};
rc = FsHvbGetValueFromCmdLine(&forceEnable[0], sizeof(forceEnable), HVB_CMDLINE_HVB_FORCE_ENABLE);
if (rc == 0 && strcmp(&forceEnable[0], "factory") == 0) {
return true;
}
rc = FsHvbGetValueFromCmdLine(&verifiedBootState[0], sizeof(verifiedBootState), HVB_CMDLINE_VERIFIEDBOOT_STATE);
if (rc != 0) {
BEGET_LOGE("error 0x%x, get verifed boot state", rc);
return false;
}
if (strcmp(&verifiedBootState[0], "orange") == 0 || strcmp(&verifiedBootState[0], "ORANGE")) {
return false;
}
return true;
}
int HvbDmVerityinit(const Fstab *fstab)
{
int rc;
FstabItem *p = NULL;
if (!HvbDmVerityIsEnable()) {
BEGET_LOGI("hvb not enable, not init");
return 0;
}
for (p = fstab->head; p != NULL; p = p->next) {
if (p->fsManagerFlags & FS_MANAGER_HVB)
break;
}
if (p == NULL) {
BEGET_LOGI("no need init fs hvb");
// return 0;
}
rc = FsHvbInit();
if (rc != 0) {
BEGET_LOGE("init fs hvb error, ret=%d", rc);
return rc;
}
return rc;
}
int HvbDmVeritySetUp(FstabItem *fsItem)
{
int rc;
if (!HvbDmVerityIsEnable()) {
BEGET_LOGI("hvb not enable, not setup");
return 0;
}
DM_VERITY_RETURN_ERR_IF_NULL(fsItem);
if ((fsItem->fsManagerFlags & FS_MANAGER_HVB) == 0) {
BEGET_LOGW("device %s not need hvb", fsItem->deviceName ? fsItem->deviceName : "none");
return 0;
}
rc = FsHvbSetupHashtree(fsItem);
if (rc != 0) {
BEGET_LOGE("error, setup hashtree fail, ret=%d", rc);
return rc;
}
return rc;
}
void HvbDmVerityFinal(void)
{
int rc;
if (!HvbDmVerityIsEnable()) {
BEGET_LOGI("hvb not enable, not final");
return;
}
rc = FsHvbFinal();
if (rc != 0) {
BEGET_LOGE("final fs hvb error, ret=%d", rc);
return;
}
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/*
* Copyright (c) 2023 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.
*/
#ifndef STARTUP_DM_VERITY_H
#define STARTUP_DM_VERITY_H
#include <stdbool.h>
#include <stdio.h>
#include "fs_manager/fs_manager.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
int HvbDmVerityinit(const Fstab *fstab);
int HvbDmVeritySetUp(FstabItem *fsItem);
void HvbDmVerityFinal(void);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif // STARTUP_DM_VERITY_H
......@@ -51,6 +51,9 @@ static unsigned int ConvertFlags(char *flagBuffer)
{"wait", FS_MANAGER_WAIT},
{"required", FS_MANAGER_REQUIRED},
{"nofail", FS_MANAGER_NOFAIL},
#ifdef SUPPORT_HVB
{"hvb", FS_MANAGER_HVB},
#endif
};
BEGET_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
......
......@@ -27,6 +27,9 @@
#include "init_utils.h"
#include "param/init_param.h"
#include "securec.h"
#ifdef SUPPORT_HVB
#include "dm_verity.h"
#endif
#ifdef __cplusplus
#if __cplusplus
......@@ -40,6 +43,17 @@ extern "C" {
const off_t MISC_PARTITION_ACTIVE_SLOT_OFFSET = 4096;
const off_t MISC_PARTITION_ACTIVE_SLOT_SIZE = 4;
#ifdef SUPPORT_HVB
__attribute__((weak)) int UeventdSocketInit(void)
{
return 0;
}
__attribute__((weak)) void RetriggerUeventByPath(int sockFd, char *path)
{
}
#endif
bool IsSupportedFilesystem(const char *fsType)
{
bool supported = false;
......@@ -435,6 +449,13 @@ static int CheckRequiredAndMount(FstabItem *item, bool required)
int bootSlots = GetBootSlots();
BEGET_INFO_CHECK(bootSlots <= 1, AdjustPartitionNameByPartitionSlot(item),
"boot slots is %d, now adjust partition name according to current slot", bootSlots);
#ifdef SUPPORT_HVB
rc = HvbDmVeritySetUp(item);
if (rc != 0) {
BEGET_LOGE("set dm_verity err, ret = 0x%x", rc);
// return rc;
}
#endif
rc = MountOneItem(item);
}
} else { // Mount partition during second startup.
......@@ -453,12 +474,28 @@ int MountAllWithFstab(const Fstab *fstab, bool required)
FstabItem *item = NULL;
int rc = -1;
#ifdef SUPPORT_HVB
if (required) {
rc = HvbDmVerityinit(fstab);
if (rc != 0) {
BEGET_LOGE("set dm_verity init, ret = 0x%x", rc);
// return rc;
}
}
#endif
for (item = fstab->head; item != NULL; item = item->next) {
rc = CheckRequiredAndMount(item, required);
if (required && (rc < 0)) { // Init fail to mount in the first stage and exit directly.
break;
}
}
#ifdef SUPPORT_HVB
if (required)
HvbDmVerityFinal();
#endif
return rc;
}
......
/*
* Copyright (c) 2022-2023 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 <fs_dm.h>
#include "securec.h"
#include "beget_ext.h"
#include <linux/dm-ioctl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include "ueventd.h"
#include "ueventd_socket.h"
#include <limits.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#define DM_VERSION0 (4)
#define DM_VERSION1 (0)
#define DM_VERSION2 (0)
#define DM_ALIGN_MASK (7)
#define DM_ALIGN(x) (((x) + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
#define DEVICE_MAPPER_PATH "/dev/mapper/control"
#define DM_DEVICE_PATH_PREFIX "/dev/block/dm-"
#define FS_DM_RETURN_ERR_IF_NULL(__ptr) \
do { \
if ((__ptr) == NULL) { \
BEGET_LOGE("error, %s is NULL\n", #__ptr); \
return -1; \
} \
} while (0)
static int InitDmIo(struct dm_ioctl *io, const char *devName)
{
errno_t err;
err = memset_s(io, sizeof(*io), 0, sizeof(*io));
if (err != EOK) {
BEGET_LOGE("memset io, ret=%d", err);
return -1;
}
io->version[0] = DM_VERSION0;
io->version[1] = DM_VERSION1;
io->version[2] = DM_VERSION2;
io->data_size = sizeof(*io);
io->data_start = 0;
if (devName == NULL) {
return 0;
}
err = strcpy_s(io->name, sizeof(io->name), devName);
if (err != EOK) {
BEGET_LOGE("cp devName, ret=%d", err);
return -1;
}
return 0;
}
static int CreateDmDevice(int fd, const char *devName)
{
int rc;
struct dm_ioctl io;
rc = InitDmIo(&io, devName);
if (rc != 0) {
return rc;
}
rc = ioctl(fd, DM_DEV_CREATE, &io);
if (rc != 0) {
BEGET_LOGE("error, DM_DEV_CREATE failed for %s, ret=%d", devName, rc);
return rc;
}
return 0;
}
static int LoadDmDeviceTable(int fd, const char *devName, DmVerityTarget *target)
{
int rc;
errno_t err;
char *parasBuf = NULL;
size_t parasTotalSize;
struct dm_ioctl *io = NULL;
struct dm_target_spec *ts = NULL;
char *paras = NULL;
FS_DM_RETURN_ERR_IF_NULL(target);
FS_DM_RETURN_ERR_IF_NULL(target->paras);
parasTotalSize = DM_ALIGN(sizeof(*io) + sizeof(*ts) + target->paras_len + 1);
parasBuf = calloc(1, parasTotalSize);
if (parasBuf == NULL) {
BEGET_LOGE("error, calloc dm table fail");
return -1;
}
io = (struct dm_ioctl *)parasBuf;
ts = (struct dm_target_spec *)(parasBuf + sizeof(*io));
paras = parasBuf + sizeof(*io) + sizeof((*ts));
do {
rc = InitDmIo(io, devName);
if (rc != 0) {
BEGET_LOGE("error 0x%x, init dm io", rc);
break;
}
io->data_size = parasTotalSize;
io->data_start = sizeof(*io);
io->target_count = 1;
io->flags |= DM_READONLY_FLAG;
ts->status = 0;
ts->sector_start = target->start;
ts->length = target->length;
err = strcpy_s(ts->target_type, sizeof(ts->target_type), "verity");
if (err != EOK) {
rc = -1;
BEGET_LOGE("error 0x%x, cp target type", err);
break;
}
err = strcpy_s(paras, target->paras_len + 1,target->paras);
if (err != EOK) {
rc = -1;
BEGET_LOGE("error 0x%x, cp target paras", err);
break;
}
ts->next = parasTotalSize - sizeof(*io);
rc = ioctl(fd, DM_TABLE_LOAD, io);
if (rc != 0) {
BEGET_LOGE("error 0x%x, DM_TABLE_LOAD failed for %s", rc, devName);
break;
}
} while (0);
free(parasBuf);
return rc;
}
static int ActiveDmDevice(int fd, const char *devName)
{
int rc;
struct dm_ioctl io;
rc = InitDmIo(&io, devName);
if (rc != 0) {
return rc;
}
io.flags |= DM_READONLY_FLAG;
rc = ioctl(fd, DM_DEV_SUSPEND, &io);
if (rc != 0) {
BEGET_LOGE("error, DM_TABLE_SUSPEND for %s, ret=%d", devName, rc);
return rc;
}
return 0;
}
int GetDmDevPath(int fd, char **dmDevPath, const char *devName)
{
int rc;
char *path = NULL;
size_t path_len = strlen(DM_DEVICE_PATH_PREFIX) + 32;
unsigned int dev_num;
struct dm_ioctl io;
rc = InitDmIo(&io, devName);
if (rc != 0) {
BEGET_LOGE("error 0x%x, init Dm io", rc);
return rc;
}
rc = ioctl(fd, DM_DEV_STATUS, &io);
if (rc != 0) {
BEGET_LOGE("error, DM_DEV_STATUS for %s, ret=%d", devName, rc);
return rc;
}
dev_num = minor(io.dev);
path = calloc(1, path_len);
if (path == NULL) {
BEGET_LOGE("error, alloc dm dev path");
return -1;
}
rc = snprintf_s(path, path_len, path_len - 1, "%s%u", DM_DEVICE_PATH_PREFIX, dev_num);
if (rc < 0) {
BEGET_LOGE("error 0x%x, cp dm dev path", rc);
free(path);
return -1;
}
*dmDevPath = path;
return 0;
}
int FsDmCreateDevice(char **dmDevPath, const char *devName, DmVerityTarget *target)
{
int rc;
int fd = -1;
fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
if (fd < 0) {
BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
return -1;
}
rc = CreateDmDevice(fd, devName);
if (rc != 0) {
BEGET_LOGE("error 0x%x, create dm device fail", rc);
return rc;
}
rc = LoadDmDeviceTable(fd, devName, target);
if (rc != 0) {
BEGET_LOGE("error 0x%x, load device table fail", rc);
return rc;
}
rc = ActiveDmDevice(fd, devName);
if (rc != 0) {
BEGET_LOGE("error 0x%x, active device fail", rc);
return rc;
}
rc = GetDmDevPath(fd, dmDevPath, devName);
if (rc != 0) {
BEGET_LOGE("error 0x%x, get dm dev fail", rc);
return rc;
}
return 0;
}
int FsDmInitDmDev(char *devPath)
{
int rc;
char dmDevPath[PATH_MAX] = {0};
char *devName = NULL;
if (devPath == NULL) {
BEGET_LOGE("error, devPath is NULL");
return -1;
}
devName = basename(devPath);
rc = snprintf_s(&dmDevPath[0], sizeof(dmDevPath), sizeof(dmDevPath) - 1, "%s%s", "/sys/block/", devName);
if (rc < 0) {
BEGET_LOGE("error 0x%x, format dm dev", rc);
return rc;
}
int ueventSockFd = UeventdSocketInit();
if (ueventSockFd < 0) {
BEGET_LOGE("error, Failed to create uevent socket");
return -1;
}
RetriggerUeventByPath(ueventSockFd, &dmDevPath[0]);
close(ueventSockFd);
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/*
* Copyright (c) 2023 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.
*/
#ifndef STARTUP_LIBFS_DM_H
#define STARTUP_LIBFS_DM_H
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "fs_manager/fs_manager.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
typedef struct {
uint64_t start;
uint64_t length;
char *paras;
uint64_t paras_len;
} DmVerityTarget;
int FsDmInitDmDev(char *devPath);
int FsDmCreateDevice(char **dmDevPath, const char *devName, DmVerityTarget *target);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif // STARTUP_LIBFS_DM_H
/*
* Copyright (c) 2022-2023 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 "fs_hvb.h"
#include "fs_dm.h"
#include "securec.h"
#include <stdint.h>
#include "beget_ext.h"
#include "init_utils.h"
#include <libhvb.h>
#include <libgen.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#define FS_HVB_VERITY_TARGET_MAX 512
#define FS_HVB_BLANK_SPACE_ASCII 32
#define FS_HVB_SECTOR_BYTES 512
#define FS_HVB_UINT64_MAX_LENGTH 64
#define FS_HVB_HASH_ALG_STR_MAX 32
#define FS_HVB_DIGEST_SHA256_BYTES 32
#define FS_HVB_DIGEST_SHA512_BYTES 64
#define FS_HVB_DIGEST_MAX_BYTES FS_HVB_DIGEST_SHA512_BYTES
#define FS_HVB_DIGEST_STR_MAX_BYTES 128
#define FS_HVB_DEVPATH_MAX_LEN 128
#define FS_HVB_RVT_PARTITION_NAME "rvt"
#define FS_HVB_CMDLINE_PATH "/proc/cmdline"
#define FS_HVB_CMDLINE_HASH_ALG "ohos.boot.hvb.hash_algo"
#define FS_HVB_CMDLINE_CERT_DIGEST "ohos.boot.rvt.digest"
#define FS_HVB_PARTITION_PREFIX "/dev/block/by-name/"
#define FS_HVB_RETURN_ERR_IF_NULL(__ptr) \
do { \
if ((__ptr) == NULL) { \
BEGET_LOGE("error, %s is NULL\n", #__ptr); \
return -1; \
} \
} while (0)
static struct hvb_verified_data *g_vd = NULL;
static char FsHvbBinToHexChar(char octet)
{
return octet < 10 ? '0' + octet : 'a' + (octet - 10);
}
static char FsHvbHexCharToBin(char hex)
{
return '0' <= hex && hex <= '9' ? hex - '0' : 10 + (hex - 'a');
}
static int FsHvbGetHashStr(char *str, size_t size)
{
return FsHvbGetValueFromCmdLine(str, size, FS_HVB_CMDLINE_HASH_ALG);
}
static int FsHvbGetCertDigstStr(char *str, size_t size)
{
return FsHvbGetValueFromCmdLine(str, size, FS_HVB_CMDLINE_CERT_DIGEST);
}
static int FsHvbComputeSha256(char *digest, size_t size, struct hvb_cert_data *certs, uint64_t num_certs)
{
int ret;
uint64_t n;
struct hash_ctx_t ctx = {0};
if (size < FS_HVB_DIGEST_SHA256_BYTES) {
BEGET_LOGE("error, size=%zu", size);
return -1;
}
ret = hash_ctx_init(&ctx, HASH_ALG_SHA256);
if (ret != HASH_OK) {
BEGET_LOGE("error 0x%x, sha256 init", ret);
return -1;
}
for (n = 0; n < num_certs; n++) {
ret = hash_calc_update(&ctx, certs[n].data.addr, certs[n].data.size);
if (ret != HASH_OK) {
BEGET_LOGE("error 0x%x, sha256 update", ret);
return -1;
}
}
ret = hash_calc_do_final(&ctx, NULL, 0, (uint8_t *)digest, size);
if (ret != HASH_OK) {
BEGET_LOGE("error 0x%x, sha256 final", ret);
return -1;
}
return 0;
}
static int FsHvbHexStrToBin(char *bin, size_t bin_size, char *str, size_t str_size)
{
size_t i;
if ((str_size & 0x1) != 0 || bin_size < (str_size >> 1)) {
BEGET_LOGE("error, bin_size %zu str_size %zu", bin_size, str_size);
return -1;
}
for (i = 0; i < (str_size >> 1); i++) {
bin[i] = (FsHvbHexCharToBin(str[2 * i]) << 4) | FsHvbHexCharToBin(str[2 * i + 1]);
}
return 0;
}
static int FsHvbCheckCertChainDigest(struct hvb_cert_data *certs, uint64_t num_certs)
{
int ret;
size_t digest_len = 0;
char hashAlg[FS_HVB_HASH_ALG_STR_MAX] = {0};
char certDigest[FS_HVB_DIGEST_MAX_BYTES] = {0};
char computeDigest[FS_HVB_DIGEST_MAX_BYTES] = {0};
char certDigestStr[FS_HVB_DIGEST_STR_MAX_BYTES + 1] = {0};
ret = FsHvbGetHashStr(&hashAlg[0], sizeof(hashAlg));
if (ret != 0) {
return ret;
}
ret = FsHvbGetCertDigstStr(&certDigestStr[0], sizeof(certDigestStr));
if (ret != 0) {
return ret;
}
ret = FsHvbHexStrToBin(&certDigest[0], sizeof(certDigest), &certDigestStr[0], strlen(certDigestStr));
if (ret != 0) {
return ret;
}
if (strcmp(&hashAlg[0], "sha256") == 0) {
digest_len = FS_HVB_DIGEST_SHA256_BYTES;
ret = FsHvbComputeSha256(computeDigest, sizeof(computeDigest), certs, num_certs);
} else {
BEGET_LOGE("error, not support alg %s", &hashAlg[0]);
return -1;
}
if (ret != 0) {
BEGET_LOGE("error 0x%x, compute hash", ret);
return -1;
}
ret = memcmp(&certDigest[0], &computeDigest[0], digest_len);
if (ret != 0) {
BEGET_LOGE("error, cert digest not match with cmdline");
return -1;
}
return 0;
}
int FsHvbInit(void)
{
enum hvb_errno rc;
// return ok if the hvb is already initialized
if (g_vd != NULL) {
BEGET_LOGI("Hvb has already been inited");
return 0;
}
rc = hvb_chain_verify(FsHvbGetOps(), FS_HVB_RVT_PARTITION_NAME, NULL, &g_vd);
if (g_vd == NULL) {
BEGET_LOGE("error 0x%x, hvb chain verify, vd is NULL", rc);
return rc;
}
if (rc != HVB_OK) {
BEGET_LOGE("error 0x%x, hvb chain verify", rc);
hvb_chain_verify_data_free(g_vd);
g_vd = NULL;
return rc;
}
rc = FsHvbCheckCertChainDigest(g_vd->certs, g_vd->num_loaded_certs);
if (rc != 0) {
BEGET_LOGE("error 0x%x, cert chain hash", rc);
hvb_chain_verify_data_free(g_vd);
g_vd = NULL;
return rc;
}
return 0;
}
static int FsHvbGetCert(struct hvb_cert *cert, char *devName, struct hvb_verified_data *vd)
{
enum hvb_errno hr;
size_t devNameLen = strlen(devName);
struct hvb_cert_data *p = vd->certs;
struct hvb_cert_data *end = p + vd->num_loaded_certs;
for (; p < end; p++) {
if (devNameLen != strlen(p->partition_name)) {
continue;
}
if (memcmp(p->partition_name, devName, devNameLen) == 0) {
break;
}
}
if (p == end) {
BEGET_LOGE("error, can't found %s partition", devName);
return -1;
}
hr = hvb_cert_parser(cert, &p->data);
if (hr != HVB_OK) {
BEGET_LOGE("error 0x%x, parser hvb cert", hr);
return -1;
}
return 0;
}
static int FsHvbVerityTargetAppendString(char **p, char *end, char *str, size_t len)
{
errno_t err;
// check range for append string
if (*p + len >= end || *p + len < *p) {
BEGET_LOGE("error, append string overflow");
return -1;
}
// append string
err = memcpy_s(*p, end - *p, str, len);
if (err != EOK) {
BEGET_LOGE("error 0x%x, cp string fail", err);
return -1;
}
*p += len;
// check range for append blank space
if (*p + 1 >= end || *p + 1 < *p) {
BEGET_LOGE("error, append blank space overflow");
return -1;
}
// append blank space
**p = FS_HVB_BLANK_SPACE_ASCII;
*p += 1;
BEGET_LOGE("append string %s", str);
return 0;
}
static int FsHvbVerityTargetAppendOctets(char **p, char *end, char *octs, size_t octs_len)
{
size_t i;
int rc;
char *str = NULL;
size_t str_len = octs_len * 2;
str = calloc(1, str_len + 1);
if (str == NULL) {
BEGET_LOGE("error, calloc str fail");
return -1;
}
for (i = 0; i < octs_len; i++) {
str[2 * i] = FsHvbBinToHexChar((octs[i] >> 4) & 0xf);
str[2 * i + 1] = FsHvbBinToHexChar(octs[i] & 0xf);
}
rc = FsHvbVerityTargetAppendString(p, end, str, str_len);
if (rc != 0)
BEGET_LOGE("error 0x%x, append str fail", rc);
free(str);
return rc;
}
static int FsHvbVerityTargetAppendNum(char **p, char *end, uint64_t num)
{
int rc;
char num_str[FS_HVB_UINT64_MAX_LENGTH] = {0};
rc = sprintf_s(&num_str[0], sizeof(num_str), "%llu", num);
if (rc < 0) {
BEGET_LOGE("error 0x%x, calloc num_str", rc);
return rc;
}
rc = FsHvbVerityTargetAppendString(p, end, num_str, strlen(&num_str[0]));
if (rc != 0) {
BEGET_LOGE("error 0x%x, append num_str fail", rc);
}
return rc;
}
#define RETURN_ERR_IF_APPEND_STRING_ERR(p, end, str, str_len) \
do { \
int __ret = FsHvbVerityTargetAppendString(p, end, str, str_len); \
if (__ret != 0) \
return __ret; \
} while (0)
#define RETURN_ERR_IF_APPEND_OCTETS_ERR(p, end, octs, octs_len) \
do { \
int __ret = FsHvbVerityTargetAppendOctets(p, end, octs, octs_len); \
if (__ret != 0) \
return __ret; \
} while (0)
#define RETURN_ERR_IF_APPEND_DIGIT_ERR(p, end, num) \
do { \
int __ret = FsHvbVerityTargetAppendNum(p, end, num); \
if (__ret != 0) \
return __ret; \
} while (0)
static char *FsHvbGetHashAlgStr(unsigned int hash_algo)
{
char *alg = NULL;
switch (hash_algo) {
case 0:
alg = "sha256";
break;
case 1:
alg = "sha512";
break;
default:
alg = NULL;
break;
}
return alg;
}
/*
* target->paras is verity table target, format as below;
* <version> <dev><hash_dev><data_block_size><hash_block_size>
* <num_data_blocks><hash_start_block><algorithm><digest><salt>
*[<#opt_params><opt_params>]
*exp: 1 /dev/sda1 /dev/sda1 4096 4096 262144 262144 sha256 \
xxxxx
xxxxx
*/
static int FsHvbConstructVerityTarget(DmVerityTarget *target, char *devName, struct hvb_cert *cert)
{
char *p = NULL;
char *end = NULL;
char *hashALgo = NULL;
char devPath[FS_HVB_DEVPATH_MAX_LEN] = {0};
target->start = 0;
target->length = cert->image_len / FS_HVB_SECTOR_BYTES;
target->paras = calloc(1, FS_HVB_VERITY_TARGET_MAX); // simple it, just calloc a big mem
if (target->paras == NULL) {
BEGET_LOGE("error, alloc target paras");
return -1;
}
if (snprintf_s(&devPath[0], sizeof(devPath), sizeof(devPath) - 1, "%s%s", FS_HVB_PARTITION_PREFIX, devName) == -1) {
BEGET_LOGE("error, snprintf_s devPath");
return -1;
}
BEGET_LOGE("puck devPath=%s", &devPath[0]);
p = target->paras;
end = p + FS_HVB_VERITY_TARGET_MAX;
// append <version>
RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, 1);
// append <dev>
RETURN_ERR_IF_APPEND_STRING_ERR(&p, end, &devPath[0], strlen(devPath));
// append <hash_dev>
RETURN_ERR_IF_APPEND_STRING_ERR(&p, end, &devPath[0], strlen(devPath));
// append <data_block_size>
RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->data_block_size);
// append <hash_block_size>
RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->hash_block_size);
// append <num_data_blocks>
RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->image_len / cert->data_block_size);
// append <hash_start_block>
RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->hashtree_offset / cert->hash_block_size);
// append <algorithm>
hashALgo = FsHvbGetHashAlgStr(cert->hash_algo);
if (hashALgo == NULL) {
BEGET_LOGE("error, hash alg %d is invalid", cert->hash_algo);
return -1;
}
RETURN_ERR_IF_APPEND_STRING_ERR(&p, end, hashALgo, strlen(hashALgo));
// append <digest>
RETURN_ERR_IF_APPEND_OCTETS_ERR(&p, end, (char *)cert->hash_payload.digest, cert->digest_size);
// append <salt>
RETURN_ERR_IF_APPEND_OCTETS_ERR(&p, end, (char *)cert->hash_payload.salt, cert->salt_size);
//remove last blank
*(p - 1) = '\0';
target->paras_len = strlen(target->paras);
return 0;
}
static int FsHvbCreateVerityTarget(DmVerityTarget *target, char *devName, struct hvb_verified_data *vd)
{
int rc;
struct hvb_cert cert = {0};
rc = FsHvbGetCert(&cert, devName, vd);
if (rc != 0) {
return rc;
}
rc = FsHvbConstructVerityTarget(target, devName, &cert);
if (rc != 0) {
BEGET_LOGE("error 0x%x, can't construct verity target", rc);
return rc;
}
return rc;
}
void FsHvbDestoryVerityTarget(DmVerityTarget *target)
{
if (target != NULL && target->paras != NULL) {
free(target->paras);
target->paras = NULL;
}
}
int FsHvbSetupHashtree(FstabItem *fsItem)
{
int rc;
DmVerityTarget target = {0};
char *dmDevPath = NULL;
char *devName = NULL;
FS_HVB_RETURN_ERR_IF_NULL(fsItem);
FS_HVB_RETURN_ERR_IF_NULL(g_vd);
// fsItem->deviceName is like /dev/block/platform/xxx/by-name/system
// we just basename system
devName = basename(fsItem->deviceName);
if (devName == NULL) {
BEGET_LOGE("error, get basename");
return -1;
}
rc = FsHvbCreateVerityTarget(&target, devName, g_vd);
if (rc != 0) {
BEGET_LOGE("error 0x%x, create verity-table", rc);
goto exit;
}
rc = FsDmCreateDevice(&dmDevPath, devName, &target);
if (rc != 0) {
BEGET_LOGE("error 0x%x, create dm-verity", rc);
goto exit;
}
rc = FsDmInitDmDev(dmDevPath);
if (rc != 0) {
BEGET_LOGE("error 0x%x, create init dm dev", rc);
goto exit;
}
free(fsItem->deviceName);
fsItem->deviceName = dmDevPath;
exit:
FsHvbDestoryVerityTarget(&target);
return rc;
}
int FsHvbFinal(void)
{
if (g_vd != NULL) {
hvb_chain_verify_data_free(g_vd);
}
return 0;
}
int FsHvbGetValueFromCmdLine(char *val, size_t size, const char *key)
{
int ret;
FS_HVB_RETURN_ERR_IF_NULL(val);
FS_HVB_RETURN_ERR_IF_NULL(key);
char *buffer = ReadFileData(FS_HVB_CMDLINE_PATH);
if (buffer == NULL) {
BEGET_LOGE("error, read %s fail", FS_HVB_CMDLINE_PATH);
return -1;
}
ret = GetProcCmdlineValue(key, buffer, val, size);
if (ret != 0) {
BEGET_LOGE("error 0x%x, get %s val from cmdline", ret, key);
}
free(buffer);
return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/*
* Copyright (c) 2022-2023 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 "beget_ext.h"
#include "fs_dm.h"
#include "fs_hvb.h"
#include "securec.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#define PARTITION_PATH_PREFIX "/dev/block/by-name/"
static int64_t GetImageSizeForHVB(const int fd, const char *image)
{
if (fd < 0) {
BEGET_LOGE("param is error");
return -1;
}
return lseek64(fd, 0, SEEK_END);
}
static enum hvb_io_errno HvbReadFromPartition(
struct hvb_ops *ops, const char *partition, int64_t offset, uint64_t numBytes, void *buf, uint64_t *outNumRead)
{
int rc;
int fd = -1;
char *path = NULL;
size_t pathLen = 0;
enum hvb_io_errno ret = HVB_IO_ERROR_IO;
if (partition == NULL) {
BEGET_LOGE("error, partition is NULL");
return HVB_IO_ERROR_IO;
}
if (buf == NULL) {
BEGET_LOGE("error, buf is NULL");
return HVB_IO_ERROR_IO;
}
pathLen = strlen(PARTITION_PATH_PREFIX) + strlen(partition);
path = calloc(1, pathLen + 1);
if (path == NULL) {
BEGET_LOGE("error, calloc fail");
return HVB_IO_ERROR_OOM;
}
rc = snprintf_s(path, pathLen + 1, pathLen, "%s%s", PARTITION_PATH_PREFIX, partition);
if (rc < 0) {
BEGET_LOGE("error, snprintf_s fail, ret = %d", rc);
ret = HVB_IO_ERROR_IO;
goto exit;
}
fd = open(path , O_RDONLY | O_CLOEXEC);
if (fd < 0) {
BEGET_LOGE("error, Failed to open %s, errno = %d", path, errno);
fd = open("/dev/block/by-name/rvt_system", O_RDONLY | O_CLOEXEC);
BEGET_LOGE("open %s, fd=%d errno = %d", "/dev/block/by-name/rvt_system", fd, errno);
if (fd >= 0)
close(fd);
ret = HVB_IO_ERROR_IO;
goto exit;
}
if (offset < 0) {
int64_t total_size = GetImageSizeForHVB(fd, partition);
if (total_size == -1) {
BEGET_LOGE("Failed to get the size of the partition %s", partition);
ret = HVB_IO_ERROR_IO;
goto exit;
}
offset = total_size + offset;
}
lseek64(fd, offset, SEEK_SET);
ssize_t numRead = read(fd, buf, numBytes);
if (numRead < 0 || (size_t)numRead != numBytes) {
BEGET_LOGE("Failed to read %lld bytes from %s offset %lld", numBytes, path, offset);
ret = HVB_IO_ERROR_IO;
goto exit;
}
if (outNumRead != NULL) {
*outNumRead = numRead;
}
ret = HVB_IO_OK;
exit:
if (path != NULL)
free(path);
if (fd >= 0)
close(fd);
return ret;
}
static enum hvb_io_errno HvbWriteToPartition(
struct hvb_ops *ops, const char *partition, int64_t offset, uint64_t numBytes, const void *buf)
{
return HVB_IO_OK;
}
static enum hvb_io_errno HvbInvaldateKey(struct hvb_ops *ops, const uint8_t *publicKeyData, uint64_t publicKeyLength,
const uint8_t *publicKeyMetadata, uint64_t publicKeyMetadataLength, bool *outIsTrusted)
{
if (outIsTrusted == NULL) {
return HVB_IO_ERROR_IO;
}
*outIsTrusted = true;
return HVB_IO_OK;
}
static enum hvb_io_errno HvbReadRollbackIdx(
struct hvb_ops *ops, uint64_t rollBackIndexLocation, uint64_t *outRollbackIndex)
{
if (outRollbackIndex == NULL) {
return HVB_IO_ERROR_IO;
}
// return 0 as we only need to set up HVB HASHTREE partitions
*outRollbackIndex = 0;
return HVB_IO_OK;
}
static enum hvb_io_errno HvbWriteRollbackIdx(
struct hvb_ops *ops, uint64_t rollBackIndexLocation, uint64_t rollbackIndex)
{
return HVB_IO_OK;
}
static enum hvb_io_errno HvbReadLockState(struct hvb_ops *ops, bool *lock_state)
{
return HVB_IO_OK;
}
static enum hvb_io_errno HvbGetSizeOfPartition(struct hvb_ops *ops, const char *partition, uint64_t *size)
{
if (size == NULL) {
return HVB_IO_ERROR_IO;
}
// The function is for bootloader to load entire content of HVB HASH
// partitions. In user-space, return 0 as we only need to set up HVB
// HASHTREE partitions.
*size = 0;
return HVB_IO_OK;
}
static struct hvb_ops g_hvb_ops = {
.user_data = &g_hvb_ops,
.read_partition = HvbReadFromPartition,
.write_partition = HvbWriteToPartition,
.valid_rvt_key = HvbInvaldateKey,
.read_rollback = HvbReadRollbackIdx,
.write_rollback = HvbWriteRollbackIdx,
.read_lock_state = HvbReadLockState,
.get_partiton_size = HvbGetSizeOfPartition,
};
struct hvb_ops *FsHvbGetOps(void)
{
return &g_hvb_ops;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/*
* Copyright (c) 2023 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.
*/
#ifndef STARTUP_LIBFS_HVB_H
#define STARTUP_LIBFS_HVB_H
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <hvb.h>
#include "fs_manager/fs_manager.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
int FsHvbInit(void);
int FsHvbSetupHashtree(FstabItem *fsItem);
int FsHvbFinal(void);
struct hvb_ops *FsHvbGetOps(void);
int FsHvbGetValueFromCmdLine(char *val, size_t size, const char *key);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif // STARTUP_LIBFS_HVB_H
......@@ -30,6 +30,7 @@ extern "C" {
#define FS_MANAGER_WAIT 0x00000002
#define FS_MANAGER_REQUIRED 0x00000004
#define FS_MANAGER_NOFAIL 0x00000008
#define FS_MANAGER_HVB 0x00000010
#define NAME_SIZE 32
#define MAX_SLOT 2
......
......@@ -74,6 +74,7 @@ extern char bootDevice[CMDLINE_VALUE_LEN_MAX];
const char *ActionString(ACTION action);
void ParseUeventMessage(const char *buffer, ssize_t length, struct Uevent *uevent);
void RetriggerUevent(int sockFd, char **devices, int num);
void RetriggerUeventByPath(int sockFd, char *path);
void ProcessUevent(int sockFd, char **devices, int num);
#ifdef __cplusplus
......
......@@ -136,7 +136,8 @@ typedef struct {
static const DYNAMIC_DEVICE_NODE DYNAMIC_DEVICES[] = {
{ DEV_NODE_PATH_PREFIX"tty", S_IFCHR | DEFAULT_RW_MODE },
{ DEV_NODE_PATH_PREFIX"binder", S_IFCHR | DEFAULT_RW_MODE },
{ DEV_NODE_PATH_PREFIX"console", S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP }
{ DEV_NODE_PATH_PREFIX"console", S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP },
{ DEV_NODE_PATH_PREFIX"mapper/control", S_IFCHR | DEFAULT_RW_MODE }
};
static void HandleRequiredDynamicDeviceNodes(const struct Uevent *uevent)
......@@ -154,6 +155,11 @@ static void HandleRequiredDynamicDeviceNodes(const struct Uevent *uevent)
continue;
}
if (strcmp(uevent->deviceName, "mapper/control") == 0) {
HandleOtherDeviceEvent(uevent);
return;
}
// Matched
mask = umask(0);
if (mknod(DYNAMIC_DEVICES[idx].dev, DYNAMIC_DEVICES[idx].mode,
......@@ -176,10 +182,17 @@ static void HandleRequiredBlockDeviceNodes(const struct Uevent *uevent, char **d
return;
}
} else if (strstr(devices[i], uevent->partitionName) != NULL ||
strstr(uevent->partitionName, "vendor") != NULL || strstr(uevent->partitionName, "system") != NULL) {
strstr(uevent->partitionName, "vendor") != NULL ||
strstr(uevent->partitionName, "system") != NULL ||
strstr(uevent->partitionName, "boot") != NULL ||
strstr(uevent->partitionName, "ramdisk") != NULL ||
strstr(uevent->partitionName, "rvt") != NULL) {
INIT_LOGI("Handle required partitionName %s", uevent->partitionName);
HandleBlockDeviceEvent(uevent);
return;
} else {
INIT_LOGI("Handle required partitionName %s", uevent->partitionName);
INIT_LOGE("Handle required device %s", devices[i]);
}
}
}
......@@ -340,6 +353,11 @@ static void Trigger(const char *path, int sockFd, char **devices, int num)
closedir(dir);
}
void RetriggerUeventByPath(int sockFd, char *path)
{
Trigger(path, sockFd, NULL, 0);
}
void RetriggerUevent(int sockFd, char **devices, int num)
{
char *buffer = ReadFileData("/proc/cmdline");
......
......@@ -512,6 +512,9 @@ void HandleOtherDeviceEvent(const struct Uevent *uevent)
// Other usb devies, do not handle it.
return;
} else {
if (strcmp(uevent->deviceName, "mapper/control") == 0) {
devName = "mapper/control";
}
if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "%s/%s", devPath, devName) == -1) {
INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor);
return;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册