!29 支持运行时文件验签

Merge pull request !29 from zhushengle/sign_verity
This commit is contained in:
openharmony_ci
2023-07-07 07:38:54 +00:00
committed by Gitee
5 changed files with 288 additions and 14 deletions
+2 -1
View File
@@ -19,7 +19,8 @@ obj-$(CONFIG_SECURITY_XPM_DEBUG) += \
ccflags-$(CONFIG_SECURITY_XPM) += \
-I$(srctree)/security/xpm/include \
-I$(srctree)/security/selinux/include \
-I$(srctree)/security/selinux
-I$(srctree)/security/selinux \
-I$(srctree)/fs
$(addprefix $(obj)/,$(obj-y)): $(obj)/flask.h
+26 -1
View File
@@ -85,6 +85,31 @@ static int xpm_check_code_segment(bool is_exec, struct vm_area_struct *vma,
return xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_NO_SIGN);
}
static void xpm_check_signature_error(struct file *file, int err_num)
{
char *full_path;
char *path;
if (file == NULL)
return;
path = __getname();
if (path == NULL) {
xpm_log_error("malloc file name failed");
return;
}
full_path = file_path(file, path, PATH_MAX - 1);
if (IS_ERR(full_path)) {
xpm_log_error("get file d_path failed");
return;
}
xpm_log_error("xpm get %s signature info failed, errno = %d", full_path, -err_num);
__putname(path);
return;
}
static int xpm_check_signature(struct vm_area_struct *vma, unsigned long prot)
{
int ret;
@@ -99,7 +124,7 @@ static int xpm_check_signature(struct vm_area_struct *vma, unsigned long prot)
/* validate signature when vma is mmap in xpm region or executable */
ret = get_exec_file_signature_info(vma->vm_file, is_exec, &info);
if (ret) {
xpm_log_error("xpm get executable file signature info failed");
xpm_check_signature_error(vma->vm_file, ret);
report_file_event(TYPE_FORMAT_UNDEF, vma->vm_file);
return ret;
}
+2
View File
@@ -158,6 +158,8 @@ static const struct xpm_event_info xpm_event[] = {
EVENT_INIT, set_init_content },
[TYPE_DEBUGFS_UNINIT] = { "debugfs uninitialized",
EVENT_INIT, set_init_content },
[TYPE_DM_DISABLE] = { "dm-verity disable",
EVENT_INIT, set_init_content },
[TYPE_FORMAT_UNDEF] = { "unkown file format",
EVENT_FILE, set_file_content },
[TYPE_ANON_EXEC] = { "anon executed",
+1
View File
@@ -19,6 +19,7 @@ enum xpm_event_id {
enum xpm_event_type {
TYPE_DEVICEFS_UNINIT = 0,
TYPE_DEBUGFS_UNINIT,
TYPE_DM_DISABLE,
TYPE_FORMAT_UNDEF,
TYPE_ANON_EXEC,
TYPE_SIGN_INVALID,
+257 -12
View File
@@ -9,7 +9,15 @@
#include <linux/rwlock_types.h>
#include <linux/rwlock.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/device-mapper.h>
#include <linux/kdev_t.h>
#include <linux/namei.h>
#include "mount.h"
#include "internal.h"
#include "exec_signature_info.h"
#include "xpm_report.h"
#include "xpm_log.h"
#define VERITY_NODE_CACHE_LIMITS 10000
#define VERITY_NODE_CACHE_RECYCLE_NUM 200
@@ -27,9 +35,244 @@ struct verity_info {
int *node_count;
};
static bool dm_verity_enable_check;
#define DM_PARTITION_PATH_MAX 20
#define DM_VERITY_INVALID_DEV ((dev_t)-1)
#define SYSTTEM_STARTUP_SECOND_STAGE "/system/bin/init"
struct dm_partition {
char path[DM_PARTITION_PATH_MAX];
int len;
dev_t s_dev;
};
static struct dm_partition dm_partition_table[] = {
{ .path = "/", .len = 1, .s_dev = DM_VERITY_INVALID_DEV },
{ .path = "/system/", .len = 8, .s_dev = DM_VERITY_INVALID_DEV },
{ .path = "/vendor/", .len = 8, .s_dev = DM_VERITY_INVALID_DEV },
{ .path = "/misc/", .len = 6, .s_dev = DM_VERITY_INVALID_DEV },
{ .path = "/sys_prod/", .len = 10, .s_dev = DM_VERITY_INVALID_DEV },
{ .path = "/chip_prod/", .len = 11, .s_dev = DM_VERITY_INVALID_DEV },
};
static struct path root_path;
static dev_t get_file_dev(struct file *file)
{
struct super_block *sb;
struct mount *mnt;
if (file->f_path.mnt == NULL)
return DM_VERITY_INVALID_DEV;
mnt = container_of(file->f_path.mnt, struct mount, mnt);
sb = mnt->mnt.mnt_sb;
if (sb == NULL)
return DM_VERITY_INVALID_DEV;
return sb->s_dev;
}
static dev_t get_dm_verity_partition_dev(const char *dir)
{
int ret;
struct path path;
struct vfsmount *mnt;
dev_t s_dev;
if (root_path.dentry == NULL) {
ret = kern_path("/", LOOKUP_DIRECTORY, &path);
if (ret) {
xpm_log_error("get / path failed.");
return DM_VERITY_INVALID_DEV;
}
} else {
ret = vfs_path_lookup(root_path.dentry, root_path.mnt, dir, LOOKUP_DIRECTORY, &path);
if (ret) {
xpm_log_error("get %s path failed.", dir);
return DM_VERITY_INVALID_DEV;
}
}
mnt = path.mnt;
if (IS_ERR(mnt) || IS_ERR(mnt->mnt_sb)) {
path_put(&path);
xpm_log_error("get %s dev failed.", dir);
return DM_VERITY_INVALID_DEV;
}
s_dev = mnt->mnt_sb->s_dev;
path_put(&path);
xpm_log_info("get %s dev=%u:%u success", dir, s_dev, MINOR(s_dev));
return s_dev;
}
static bool find_partition_dev(struct file *file)
{
char *full_path = NULL;
char path[PATH_MAX] = {0};
struct dm_partition *dm_path;
int i;
for (i = 1; i < sizeof(dm_partition_table) / sizeof(struct dm_partition); i++) {
dm_path = &dm_partition_table[i];
if (dm_path->s_dev != DM_VERITY_INVALID_DEV)
continue;
if (full_path == NULL) {
full_path = file_path(file, path, PATH_MAX-1);
if (IS_ERR(full_path))
return false;
}
if (strncmp(dm_path->path, full_path, dm_path->len) != 0)
continue;
dm_path->s_dev = get_dm_verity_partition_dev(dm_path->path);
if (dm_path->s_dev == DM_VERITY_INVALID_DEV)
return false;
if (dm_path->s_dev == get_file_dev(file))
return true;
return false;
}
return false;
}
static bool dm_verity_check_for_path(struct file *file)
{
static int system_startup_stage;
char *full_path;
char path[PATH_MAX] = {0};
struct dm_partition *dm_path;
dev_t s_dev;
int i, ret;
s_dev = get_file_dev(file);
if (!system_startup_stage) {
full_path = file_path(file, path, PATH_MAX - 1);
if (IS_ERR(full_path))
return false;
if (strcmp(SYSTTEM_STARTUP_SECOND_STAGE, full_path) != 0) {
dm_path = &dm_partition_table[0];
if (dm_path->s_dev == s_dev)
return true;
return false;
}
ret = kern_path("/", LOOKUP_DIRECTORY, &root_path);
if (ret) {
xpm_log_error("get / path failed.");
return false;
}
system_startup_stage = 1;
}
for (i = 1; i < sizeof(dm_partition_table) / sizeof(struct dm_partition); i++) {
dm_path = &dm_partition_table[i];
if (dm_path->s_dev == s_dev)
return true;
}
return find_partition_dev(file);
}
#ifdef CONFIG_DM_VERITY
#define HVB_CMDLINE_VB_STATE "ohos.boot.hvb.enable"
static bool dm_verity_enable;
static int hvb_boot_param_cb(char *param, char *val,
const char *unused, void *arg)
{
if (param == NULL || val == NULL)
return 0;
if (strcmp(param, HVB_CMDLINE_VB_STATE) != 0)
return 0;
if (strcmp(val, "true") == 0 || strcmp(val, "TRUE") == 0)
dm_verity_enable = true;
return 0;
}
static bool dm_verity_is_enable(void)
{
char *cmdline;
if (dm_verity_enable || dm_verity_enable_check)
return dm_verity_enable;
cmdline = kstrdup(saved_command_line, GFP_KERNEL);
if (cmdline == NULL)
return false;
parse_args("hvb.enable params", cmdline, NULL,
0, 0, 0, NULL, &hvb_boot_param_cb);
kfree(cmdline);
dm_verity_enable_check = true;
if (!dm_verity_enable) {
dm_partition_table[0].s_dev = get_dm_verity_partition_dev(dm_partition_table[0].path);
report_init_event(TYPE_DM_DISABLE);
}
return dm_verity_enable;
}
static bool dm_verity_check_for_mnt(struct file *file)
{
struct mapped_device *device;
device = dm_get_md(get_file_dev(file));
if (device == NULL)
return false;
dm_put(device);
return true;
}
#endif
static bool is_dm_verity(struct file *file)
{
#ifdef CONFIG_DM_VERITY
if (dm_verity_is_enable())
return dm_verity_check_for_mnt(file);
#endif
if (!dm_verity_enable_check) {
dm_partition_table[0].s_dev = get_dm_verity_partition_dev(dm_partition_table[0].path);
dm_verity_enable_check = true;
report_init_event(TYPE_DM_DISABLE);
}
return dm_verity_check_for_path(file);
}
#ifdef CONFIG_FS_VERITY
static bool is_fs_verity(struct file *file)
{
struct inode *file_node;
file_node = file_inode(file);
if (file_node == NULL)
return false;
if (file_node->i_verity_info == NULL)
return false;
return true;
}
#endif
static int check_exec_file_is_verity(struct file *file)
{
return FILE_SIGNATURE_DM_VERITY;
#ifdef CONFIG_FS_VERITY
if (is_fs_verity(file))
return FILE_SIGNATURE_FS_VERITY;
#endif
if (is_dm_verity(file))
return FILE_SIGNATURE_DM_VERITY;
return FILE_SIGNATURE_INVALID;
}
static struct exec_file_signature_info *rb_search_node(struct rb_root *root, uintptr_t file_inode)
@@ -140,24 +383,25 @@ static size_t test_elf_code_segment_info_size(struct rb_root *root)
static void test_printf_code_segment_cache_size(void)
{
size_t cache_size = 0;
int count = 0;
int dm_count;
int fs_count;
read_lock(&dm_verity_tree_lock);
cache_size += test_elf_code_segment_info_size(&dm_verity_tree);
count += dm_verity_node_count;
dm_count = dm_verity_node_count;
read_unlock(&dm_verity_tree_lock);
read_lock(&fs_verity_tree_lock);
cache_size += test_elf_code_segment_info_size(&fs_verity_tree);
count += fs_verity_node_count;
fs_count = fs_verity_node_count;
read_unlock(&fs_verity_tree_lock);
pr_info("[exec signature cache] count=%d, cache size=%d KB\n", count, cache_size / 1024);
xpm_log_info("cache dm count=%d, fs count=%d, cache size=%d KB\n", dm_count, fs_count, cache_size / 1024);
}
static void test_print_elf_code_segment_info(struct file *file, const struct exec_file_signature_info *file_info)
static void test_print_info(struct file *file, unsigned int type, const struct exec_file_signature_info *file_info)
{
char *ret_path;
char *full_path;
char path[PATH_MAX] = {0};
static int code_segment_test_count = 100;
int i;
@@ -166,13 +410,14 @@ static void test_print_elf_code_segment_info(struct file *file, const struct exe
if (code_segment_test_count > 0)
return;
ret_path = file_path(file, path, PATH_MAX-1);
if (IS_ERR(ret_path))
full_path = file_path(file, path, PATH_MAX - 1);
if (IS_ERR(full_path))
return;
for (i = 0; i < file_info->code_segment_count; i++)
pr_info("[exec signature segment] %s -> offset: 0x%llx size: 0x%lx\n",
ret_path, file_info->code_segments->file_offset, file_info->code_segments->size);
xpm_log_info("%s -> type: %s, info: offset=0x%llx size=0x%lx\n",
full_path, type == FILE_SIGNATURE_DM_VERITY ? "dm" : "fs",
file_info->code_segments->file_offset, file_info->code_segments->size);
code_segment_test_count = 100;
}
@@ -279,7 +524,7 @@ need_parse:
if (ret < 0)
return ret;
#ifdef CONFIG_SECURITY_XPM_DEBUG
test_print_elf_code_segment_info(file, new_info);
test_print_info(file, type, new_info);
#endif
}