diff --git a/LICENSE b/LICENSE index 9b69d208ea3311b95fca9bb4d4d7fbca74e007ad..563f85698ae9b08226c80948f00c03f0fc1d6218 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ (1) The directories below are licensed under GPL-2.0-or-later. ./newip/ +(2) The directories below are licensed under GPL-2.0-only. + ./xpm/validator As for the specific use of the licenses, please refer to the relevant description in the documents. diff --git a/xpm/Makefile b/xpm/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..54d2d497030210c85e2000a80f8a2d13242df04f --- /dev/null +++ b/xpm/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2023 Huawei Device Co., Ltd. +# +# Makefile for the ecutable permission manager(XPM) module +# + +obj-$(CONFIG_XPM) += \ + validator/elf_code_segment_info.o \ + validator/exec_signature_info.o + +ccflags-$(CONFIG_XPM) += \ + -I$(srctree)/security/xpm/validator \ diff --git a/xpm/validator/elf_code_segment_info.c b/xpm/validator/elf_code_segment_info.c new file mode 100644 index 0000000000000000000000000000000000000000..6af31bc5dcd8dc86666cf9cc54cc243806631fcf --- /dev/null +++ b/xpm/validator/elf_code_segment_info.c @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#include +#include +#include +#include +#include "exec_signature_info.h" + +#if ELF_EXEC_PAGESIZE > PAGE_SIZE +#define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE +#else +#define ELF_MIN_ALIGN PAGE_SIZE +#endif + +struct elf_info { + struct elfhdr elf_ehdr; + uint16_t type; + uint16_t e_phnum; + size_t e_phsize; + uintptr_t e_phoff; +}; + +static int read_elf_info(struct file *file, void *buffer, size_t read_size, loff_t pos) +{ + size_t len; + + len = kernel_read(file, buffer, read_size, &pos); + if (unlikely(len != read_size)) + return -EIO; + + return 0; +} + +static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le64_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be64_to_cpu(value); + + return value; +} + +static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le32_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be32_to_cpu(value); + + return value; +} + +static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le16_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be16_to_cpu(value); + + return value; +} + +static int get_elf32_code_segment_count(struct elf32_phdr *elf_phdr, + struct elf_info *elf_info) +{ + int i; + int count = 0; + struct elf32_phdr *phdr_info; + uint32_t p_flags; + + for (i = 0; i < elf_info->e_phnum; i++) { + phdr_info = elf_phdr + i; + p_flags = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_flags); + if (!(p_flags & PF_X)) + continue; + + count++; + } + return count; +} + +static int get_elf32_code_segment(struct elf32_phdr *elf_phdr, struct elf_info *elf_info, + struct exec_file_signature_info *exec_file_info) +{ + int i; + struct elf32_phdr *phdr_info; + uint32_t p_flags; + uint32_t p_offset; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_addr; + + for (i = 0; i < elf_info->e_phnum; i++) { + phdr_info = elf_phdr + i; + p_flags = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_flags); + if (!(p_flags & PF_X)) + continue; + + p_offset = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_offset); + p_filesz = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_filesz); + p_addr = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_paddr); + p_memsz = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_memsz); + if (p_offset + p_filesz < p_offset || p_addr + p_memsz < p_addr) + return -ENOEXEC; + + exec_file_info->code_segments[exec_file_info->code_segment_count].file_offset = p_offset; + exec_file_info->code_segments[exec_file_info->code_segment_count].size = p_filesz; + exec_file_info->code_segment_count++; + } + return 0; +} + +static int get_elf64_code_segment_count(struct elf64_phdr *elf_phdr, struct elf_info *elf_info) +{ + int i; + int count = 0; + struct elf64_phdr *phdr_info; + uint32_t p_flags; + + for (i = 0; i < elf_info->e_phnum; i++) { + phdr_info = elf_phdr + i; + p_flags = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_flags); + if (!(p_flags & PF_X)) + continue; + + count++; + } + return count; +} + +static int get_elf64_code_segment(struct elf64_phdr *elf_phdr, struct elf_info *elf_info, + struct exec_file_signature_info *exec_file_info) +{ + int i; + struct elf64_phdr *phdr_info; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_addr; + + for (i = 0; i < elf_info->e_phnum; i++) { + phdr_info = elf_phdr + i; + p_flags = elf32_to_cpu(&elf_info->elf_ehdr, phdr_info->p_flags); + if (!(p_flags & PF_X)) + continue; + + p_offset = elf64_to_cpu(&elf_info->elf_ehdr, phdr_info->p_offset); + p_filesz = elf64_to_cpu(&elf_info->elf_ehdr, phdr_info->p_filesz); + p_addr = elf64_to_cpu(&elf_info->elf_ehdr, phdr_info->p_paddr); + p_memsz = elf64_to_cpu(&elf_info->elf_ehdr, phdr_info->p_memsz); + if (p_offset + p_filesz < p_offset || p_addr + p_memsz < p_addr) + return -ENOEXEC; + + exec_file_info->code_segments[exec_file_info->code_segment_count].file_offset = p_offset; + exec_file_info->code_segments[exec_file_info->code_segment_count].size = p_filesz; + exec_file_info->code_segment_count++; + } + return 0; +} + +static int elf_check_and_get_code_segment_offset(struct file *file, struct elf_info *elf_info) +{ + struct elf32_hdr *elf32_ehdr; + struct elf64_hdr *elf64_ehdr; + uint32_t e32_phoff; + uint32_t e32_phsize; + uint64_t e64_phoff; + uint64_t e64_phsize; + uint16_t type; + uint16_t e_ehsize; + struct elfhdr *elf_ehdr = &elf_info->elf_ehdr; + int ret; + + ret = read_elf_info(file, (void *)elf_ehdr, sizeof(struct elfhdr), 0); + if (ret < 0) + return ret; + + if (memcmp(elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0) + return -ENOEXEC; + + type = elf16_to_cpu(elf_ehdr, elf_ehdr->e_type); + if (type != ET_EXEC && type != ET_DYN) + return -ENOEXEC; + + if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS32) { + elf_info->type = ELFCLASS32; + elf32_ehdr = (struct elf32_hdr *)elf_ehdr; + e_ehsize = elf16_to_cpu(elf_ehdr, elf32_ehdr->e_ehsize); + if (e_ehsize != sizeof(struct elf32_hdr)) + return -ENOEXEC; + + elf_info->e_phnum = elf16_to_cpu(elf_ehdr, elf32_ehdr->e_phnum); + e32_phsize = sizeof(struct elf32_phdr) * elf_info->e_phnum; + if (e32_phsize == 0 || e32_phsize > 65536 || e32_phsize > ELF_MIN_ALIGN) + return -ENOEXEC; + + e32_phoff = elf32_to_cpu(elf_ehdr, elf32_ehdr->e_phoff); + if (e32_phoff + e32_phsize < e32_phoff) + return -ENOEXEC; + + elf_info->e_phsize = e32_phsize; + elf_info->e_phoff = e32_phoff; + } else if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS64) { + elf_info->type = ELFCLASS64; + elf64_ehdr = (struct elf64_hdr *)elf_ehdr; + e_ehsize = elf16_to_cpu(elf_ehdr, elf64_ehdr->e_ehsize); + if (e_ehsize != sizeof(struct elf64_hdr)) + return -ENOEXEC; + + elf_info->e_phnum = elf16_to_cpu(elf_ehdr, elf64_ehdr->e_phnum); + e64_phsize = sizeof(struct elf64_phdr) * elf_info->e_phnum; + if (e64_phsize == 0 || e64_phsize > 65536 || e64_phsize > ELF_MIN_ALIGN) + return -ENOEXEC; + + e64_phoff = elf64_to_cpu(elf_ehdr, elf64_ehdr->e_phoff); + if (e64_phoff + e64_phsize < e64_phoff) + return -ENOEXEC; + + elf_info->e_phsize = e64_phsize; + elf_info->e_phoff = e64_phoff; + } else + return -ENOEXEC; + + return 0; +} + +static int find_elf_code_segment_info(const char *phdr_info, struct elf_info *elf_info, + struct exec_file_signature_info **file_info) +{ + int ret; + size_t size; + struct exec_file_signature_info *exec_file_info; + int segment_count; + + if (elf_info->type == ELFCLASS32) + segment_count = get_elf32_code_segment_count((struct elf32_phdr *)phdr_info, elf_info); + else + segment_count = get_elf64_code_segment_count((struct elf64_phdr *)phdr_info, elf_info); + + if (segment_count == 0) + return -ENOEXEC; + + size = sizeof(struct exec_file_signature_info) + segment_count * sizeof(struct exec_segment_info); + exec_file_info = kzalloc(size, GFP_KERNEL); + if (exec_file_info == NULL) + return -ENOMEM; + + exec_file_info->code_segments = (struct exec_segment_info *)((char *)exec_file_info + + sizeof(struct exec_file_signature_info)); + if (elf_info->type == ELFCLASS32) + ret = get_elf32_code_segment((struct elf32_phdr *)phdr_info, elf_info, exec_file_info); + else + ret = get_elf64_code_segment((struct elf64_phdr *)phdr_info, elf_info, exec_file_info); + + if (ret < 0) { + kfree(exec_file_info); + return ret; + } + *file_info = exec_file_info; + return 0; +} + +int parse_elf_code_segment_info(struct file *file, + struct exec_file_signature_info **code_segment_info) +{ + const char *phdr_info; + struct elf_info elf_info = {0}; + int ret; + + ret = elf_check_and_get_code_segment_offset(file, &elf_info); + if (ret < 0) + return ret; + + phdr_info = kzalloc(elf_info.e_phsize, GFP_KERNEL); + if (phdr_info == NULL) + return -ENOMEM; + + ret = read_elf_info(file, (void *)phdr_info, elf_info.e_phsize, elf_info.e_phoff); + if (ret < 0) { + kfree(phdr_info); + return ret; + } + + ret = find_elf_code_segment_info(phdr_info, &elf_info, code_segment_info); + kfree(phdr_info); + return ret; +} diff --git a/xpm/validator/exec_signature_info.c b/xpm/validator/exec_signature_info.c new file mode 100644 index 0000000000000000000000000000000000000000..783cf9b0b5a813dc2cc790f00521af173b37d394 --- /dev/null +++ b/xpm/validator/exec_signature_info.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include "exec_signature_info.h" + +#define VERITY_NODE_CACHE_LIMITS 10000 +#define VERITY_NODE_CACHE_RECYCLE_NUM 200 + +static DEFINE_RWLOCK(dm_verity_tree_lock); +static struct rb_root dm_verity_tree = RB_ROOT; +static int dm_verity_node_count; +static DEFINE_RWLOCK(fs_verity_tree_lock); +static struct rb_root fs_verity_tree = RB_ROOT; +static int fs_verity_node_count; + +#ifdef CONFIG_FS_VERITY +static bool is_fs_verity(struct file *file) +{ + struct inode *file_node; + + file_inode = 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) +{ +#ifdef CONFIG_FS_VERITY + if (is_fs_verity(file)) + return FILE_SIGNATURE_FS_VERITY; +#endif + + return FILE_SIGNATURE_DM_VERITY; +} + +static struct exec_file_signature_info *rb_search_node(struct rb_root *root, uintptr_t file_inode) +{ + struct rb_node *node = root->rb_node; + struct exec_file_signature_info *file_node; + + while (node != NULL) { + file_node = rb_entry(node, struct exec_file_signature_info, rb_node); + if (file_inode < file_node->inode) { + node = file_node->rb_node.rb_left; + } else if (file_inode > file_node->inode) { + node = file_node->rb_node.rb_right; + } else { + atomic_inc(&file_node->reference); + return file_node; + } + } + return NULL; +} + +static struct exec_file_signature_info *rb_add_node(struct rb_root *root, int *node_count, + struct exec_file_signature_info *node) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + struct exec_file_signature_info *file; + + while (*p != NULL) { + parent = *p; + file = rb_entry(parent, struct exec_file_signature_info, rb_node); + if (node->inode < file->inode) { + p = &(*p)->rb_left; + } else if (node->inode > file->inode) { + p = &(*p)->rb_right; + } else { + atomic_inc(&file->reference); + return file; + } + } + + rb_link_node(&node->rb_node, parent, p); + rb_insert_color(&node->rb_node, root); + atomic_inc(&node->reference); + (*node_count)++; + return NULL; +} + +static void rb_erase_node(struct rb_root *root, int *node_count, + struct exec_file_signature_info *node) +{ + rb_erase(&node->rb_node, root); + (*node_count)--; +} + +static int find_idle_nodes(struct rb_root *root, uintptr_t *ilde_nodes, size_t count) +{ + int i = 0; + struct exec_file_signature_info *code_segment; + struct rb_node *node; + + for (node = rb_first(root); node != NULL && i < count; node = rb_next(node)) { + code_segment = rb_entry(node, struct exec_file_signature_info, rb_node); + if (atomic_read(&code_segment->reference) > 0) + continue; + + ilde_nodes[i++] = (uintptr_t)code_segment; + } + return i; +} + +static void clear_code_segment_info_cache(struct rb_root *root, int *node_count) +{ + struct exec_file_signature_info *code_segment_info; + uintptr_t *code_segments; + int i = 0; + int count = VERITY_NODE_CACHE_RECYCLE_NUM; + + code_segments = kcalloc(count, sizeof(uintptr_t), GFP_KERNEL); + if (code_segments == NULL) + return; + + count = find_idle_nodes(root, code_segments, count); + while (i < count) { + code_segment_info = (struct exec_file_signature_info *)code_segments[i]; + rb_erase_node(root, node_count, code_segment_info); + kfree(code_segment_info); + i++; + } + kfree(code_segments); +} + +#ifdef CONFIG_XPM_DEBUG +static size_t test_elf_code_segment_info_size(struct rb_root *root) +{ + size_t size = 0; + struct exec_file_signature_info *file_node; + struct rb_node *node; + + for (node = rb_first(root); node != NULL; node = rb_next(node)) { + file_node = rb_entry(node, struct exec_file_signature_info, rb_node); + size += sizeof(struct exec_file_signature_info) + + file_node->code_segment_count * sizeof(struct exec_segment_info); + } + return size; +} + +static void test_printf_code_segment_cache_size(void) +{ + size_t cache_size = 0; + int count = 0; + + read_lock(&dm_verity_tree_lock); + cache_size += test_elf_code_segment_info_size(&dm_verity_tree); + 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; + read_unlock(&fs_verity_tree_lock); + + pr_info("[exec signature cache] count=%d, cache size=%d KB\n", count, cache_size / 1024); +} + +static void test_print_elf_code_segment_info(struct file *file, const struct exec_file_signature_info *file_info) +{ + char *ret_path; + char path[PATH_MAX] = {0}; + static int code_segment_test_count = 100; + int i; + + code_segment_test_count--; + if (code_segment_test_count > 0) + return; + + ret_path = file_path(file, path, PATH_MAX-1); + if (IS_ERR(ret_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); + } + + code_segment_test_count = 100; +} +#endif + +static void rm_code_segment_info(void) +{ + if (dm_verity_node_count + fs_verity_node_count < VERITY_NODE_CACHE_LIMITS) + return; + +#ifdef CONFIG_XPM_DEBUG + test_printf_code_segment_cache_size(); +#endif + + if (dm_verity_node_count > fs_verity_node_count) { + write_lock(&dm_verity_tree_lock); + clear_code_segment_info_cache(&dm_verity_tree, &dm_verity_node_count); + write_unlock(&dm_verity_tree_lock); + return; + } + + write_lock(&fs_verity_tree_lock); + clear_code_segment_info_cache(&fs_verity_tree, &fs_verity_node_count); + write_unlock(&fs_verity_tree_lock); +} + +static int get_elf_code_segment_info(struct file *file, bool is_exec, int type, + struct exec_file_signature_info **code_segment_info) +{ + int ret; + struct rb_root *root; + rwlock_t *verity_lock; + int *node_count; + struct inode *file_node; + struct exec_file_signature_info *new_info; + struct exec_file_signature_info *tmp_info; + + if (type == FILE_SIGNATURE_DM_VERITY) { + root = &dm_verity_tree; + verity_lock = &dm_verity_tree_lock; + node_count = &dm_verity_node_count; + } else if (type == FILE_SIGNATURE_FS_VERITY) { + verity_lock = &fs_verity_tree_lock; + root = &fs_verity_tree; + node_count = &fs_verity_node_count; + } else { + return -EINVAL; + } + + file_node = file_inode(file); + if (file_node == NULL) + return -EINVAL; + + read_lock(verity_lock); + tmp_info = rb_search_node(root, (uintptr_t)file_node); + read_unlock(verity_lock); + if (tmp_info != NULL) { + if (is_exec && tmp_info->code_segments == NULL) + goto need_parse; + + *code_segment_info = tmp_info; + return 0; + } + +need_parse: + rm_code_segment_info(); + + if (!is_exec) { + new_info = kzalloc(sizeof(struct exec_file_signature_info), GFP_KERNEL); + if (new_info == NULL) + return -ENOMEM; + } else { + ret = parse_elf_code_segment_info(file, &new_info); + if (ret < 0) + return ret; +#ifdef CONFIG_XPM_DEBUG + test_print_elf_code_segment_info(file, new_info); +#endif + } + + new_info->type = type; + new_info->inode = (uintptr_t)file_node; + RB_CLEAR_NODE(&new_info->rb_node); + if (tmp_info != NULL) { + write_lock(verity_lock); + rb_erase_node(root, node_count, tmp_info); + tmp_info->type |= FILE_SIGNATURE_DELETE; + write_unlock(verity_lock); + if (atomic_sub_return(1, &tmp_info->reference) <= 0) + kfree(tmp_info); + } + + write_lock(verity_lock); + tmp_info = rb_add_node(root, node_count, new_info); + write_unlock(verity_lock); + if (tmp_info != NULL) { + kfree(new_info); + new_info = tmp_info; + } + *code_segment_info = new_info; + return 0; +} + +int get_exec_file_signature_info(struct file *file, bool is_exec, + struct exec_file_signature_info **info_ptr) +{ + int type; + + if (file == NULL || info_ptr == NULL) + return -EINVAL; + + type = check_exec_file_is_verity(file); + return get_elf_code_segment_info(file, is_exec, type, info_ptr); +} + +int put_exec_file_signature_info(struct exec_file_signature_info *exec_info) +{ + if ((exec_info == NULL) || + !exec_file_signature_is_verity(exec_info)) + return -EINVAL; + + if (atomic_sub_return(1, &exec_info->reference) <= 0 && + exec_file_signature_is_delete(exec_info)) + kfree(exec_info); + return 0; +} + +static struct exec_file_signature_info *elf_code_segment_info_delete(struct rb_root *root, + int *node_count, struct inode *file_node) +{ + struct exec_file_signature_info *signature_info; + + signature_info = rb_search_node(root, (uintptr_t)file_node); + if (signature_info != NULL) { + rb_erase_node(root, node_count, signature_info); + if (atomic_sub_return(1, &signature_info->reference) > 0) + signature_info->type |= FILE_SIGNATURE_DELETE; + else + kfree(signature_info); + } + return signature_info; +} + +void delete_exec_file_signature_info(struct inode *file_node) +{ + struct exec_file_signature_info *signature_info; + + if (file_node == NULL) + return; + + write_lock(&fs_verity_tree_lock); + signature_info = elf_code_segment_info_delete(&fs_verity_tree, &fs_verity_node_count, file_node); + write_unlock(&fs_verity_tree_lock); + if (signature_info != NULL) + return; + + write_lock(&dm_verity_tree_lock); + signature_info = elf_code_segment_info_delete(&dm_verity_tree, &dm_verity_node_count, file_node); + write_unlock(&dm_verity_tree_lock); +} diff --git a/xpm/validator/exec_signature_info.h b/xpm/validator/exec_signature_info.h new file mode 100644 index 0000000000000000000000000000000000000000..1bf46ceb9aab6893d2124f57fc943c3b011f4f78 --- /dev/null +++ b/xpm/validator/exec_signature_info.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#ifndef _EXEC_SIGNATURE_INFO_H +#define _EXEC_SIGNATURE_INFO_H + +#include +#include +#include +#include + +struct exec_segment_info { + uintptr_t file_offset; + size_t size; +}; + +#define FILE_SIGNATURE_INVALID 0 +#define FILE_SIGNATURE_FS_VERITY 1 +#define FILE_SIGNATURE_DM_VERITY 2 +#define FILE_SIGNATURE_MASK 0x0000000F +#define FILE_SIGNATURE_DELETE 0x80000000 + +struct exec_file_signature_info { + struct rb_node rb_node; + atomic_t reference; + unsigned int type; + uintptr_t inode; + unsigned int code_segment_count; + struct exec_segment_info *code_segments; +}; + +static inline bool exec_file_signature_is_fs_verity(const struct exec_file_signature_info *signature_info) +{ + return (signature_info->type & FILE_SIGNATURE_MASK) == FILE_SIGNATURE_FS_VERITY; +} + +static inline bool exec_file_signature_is_dm_verity(const struct exec_file_signature_info *signature_info) +{ + return (signature_info->type & FILE_SIGNATURE_MASK) == FILE_SIGNATURE_DM_VERITY; +} + +static inline bool exec_file_signature_is_verity(const struct exec_file_signature_info *signature_info) +{ + return (signature_info->type & FILE_SIGNATURE_MASK) == FILE_SIGNATURE_DM_VERITY || + (signature_info->type & FILE_SIGNATURE_MASK) == FILE_SIGNATURE_FS_VERITY; +} + +static inline bool exec_file_signature_is_delete(const struct exec_file_signature_info *signature_info) +{ + return !!(signature_info->type & FILE_SIGNATURE_DELETE); +} + +int parse_elf_code_segment_info(struct file *file, struct exec_file_signature_info **code_segment_info); +int get_exec_file_signature_info(struct file *file, bool is_exec, struct exec_file_signature_info **info_ptr); +int put_exec_file_signature_info(struct exec_file_signature_info *exec_info); +void delete_exec_file_signature_info(struct inode *file_node); +#endif