!70 common_modules:内核侧代码所有者校验

Merge pull request !70 from 团辉/master
This commit is contained in:
openharmony_ci
2023-11-23 13:39:24 +00:00
committed by Gitee
32 changed files with 1208 additions and 769 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ ccflags-$(CONFIG_SECURITY_CODE_SIGN) += \
-I$(srctree)/fs/code_sign \
-I$(srctree)/security/selinux/include \
-I$(srctree)/security/selinux \
-I$(srctree)/security/xpm/include
-I$(srctree)/security/xpm/developer
$(addprefix $(obj)/,$(obj-y)): $(obj)/flask.h
+1 -1
View File
@@ -176,7 +176,7 @@ out:
int elf_file_enable_fs_verity(struct file *file)
{
/* developer mode */
if (strcmp(developer_mode_state(), DEVELOPER_STATUS_ON)) {
if (get_developer_mode_state() != STATE_ON) {
code_sign_log_info("developer mode off, elf not allowed to execute");
return -EINVAL;
}
+23
View File
@@ -5,10 +5,13 @@
#include <linux/code_sign.h>
#include <linux/fsverity.h>
#include <linux/stringhash.h>
#include "code_sign_ext.h"
#include "code_sign_log.h"
static time64_t cs_salt;
/**
* Validate code sign descriptor
*
@@ -82,3 +85,23 @@ void code_sign_after_measurement(void *_desc, int version)
desc->version = version;
}
}
void code_sign_init_salt(void)
{
cs_salt = ktime_get_real_seconds();
}
void code_sign_set_ownerid(struct cs_info *cs_info, uint32_t id_type,
const char *id_str, uint32_t id_len)
{
if (!cs_info) {
code_sign_log_error("Input cs_info is NULL");
return;
}
cs_info->id_type = id_type;
if (!id_str || id_len == 0)
cs_info->ownerid = 0;
else
cs_info->ownerid = full_name_hash(cs_salt, id_str, id_len);
}
+33
View File
@@ -6,6 +6,34 @@
#ifndef _CODE_SIGN_EXT_H
#define _CODE_SIGN_EXT_H
#include <linux/xpm_types.h>
#define OWNERID_SYSTEM_TAG "SYSTEM_LIB_ID"
#define OWNERID_DEBUG_TAG "DEBUG_LIB_ID"
#define OWNERID_SHARED_TAG "SHARED_LIB_ID"
#define OWNERID_COMPAT_TAG "COMPAT_LIB_ID"
enum file_ownerid_type {
FILE_OWNERID_UNINT = 0,
FILE_OWNERID_SYSTEM,
FILE_OWNERID_APP,
FILE_OWNERID_DEBUG,
FILE_OWNERID_SHARED,
FILE_OWNERID_COMPAT,
FILE_OWNERID_MAX
};
/* process and file ownerid types need to correspond to each other */
enum process_ownerid_type {
PROCESS_OWNERID_UNINIT = FILE_OWNERID_UNINT,
PROCESS_OWNERID_SYSTEM = FILE_OWNERID_SYSTEM,
PROCESS_OWNERID_APP = FILE_OWNERID_APP,
PROCESS_OWNERID_DEBUG = FILE_OWNERID_DEBUG,
PROCESS_OWNERID_COMPAT = FILE_OWNERID_COMPAT,
PROCESS_OWNERID_EXTEND,
PROCESS_OWNERID_MAX
};
/*
* code_sign_ext.c
*/
@@ -16,4 +44,9 @@ void code_sign_before_measurement(void *_desc, int *ret);
void code_sign_after_measurement(void *_desc, int version);
void code_sign_init_salt(void);
void code_sign_set_ownerid(struct cs_info *cs_info, uint32_t id_type,
const char *id_str, uint32_t id_len);
#endif /* _CODE_SIGN_H */
+2 -2
View File
@@ -9,7 +9,7 @@
#include <linux/compat.h>
#include "avc.h"
#include "objsec.h"
#include "../../security/xpm/include/dsmm_developer.h"
#include "dsmm_developer.h"
#include "code_sign_ioctl.h"
#include "code_sign_log.h"
@@ -231,7 +231,7 @@ int code_sign_check_code(int code)
return is_dev_mode;
// developer mode
if (!strcmp(developer_mode_state(), DEVELOPER_STATUS_ON)) {
if (get_developer_mode_state() == STATE_ON) {
code_sign_log_debug("developer mode on");
is_dev_mode = 1;
}
+4
View File
@@ -37,6 +37,10 @@ static void code_sign_register_hck_hooks(void)
static int __init code_sign_init(void)
{
code_sign_log_info("INIT");
/* init module init real time as salt for ownerid calculate */
code_sign_init_salt();
code_sign_register_hck_hooks();
return misc_register(&code_sign_misc);
}
+43 -3
View File
@@ -9,7 +9,8 @@
#include <linux/verification.h>
#include <crypto/pkcs7.h>
#include "objsec.h"
#include "../../security/xpm/include/dsmm_developer.h"
#include "dsmm_developer.h"
#include "code_sign_ext.h"
#include "code_sign_ioctl.h"
#include "code_sign_log.h"
#include "verify_cert_chain.h"
@@ -62,6 +63,43 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
return 0;
}
static void set_file_ownerid(struct cs_info *cs_info, int path_type,
struct pkcs7_signed_info *sinfo)
{
/* Mark a debug file as OWNERID_DEBUG */
if((path_type > DEBUG_CODE_START) && (path_type < DEBUG_CODE_END)) {
code_sign_set_ownerid(cs_info, FILE_OWNERID_DEBUG, NULL, 0);
return;
}
/* Mark the file as OWNERID_COMPAT, if its ownerid is empty */
if(!sinfo->ownerid) {
code_sign_set_ownerid(cs_info, FILE_OWNERID_COMPAT, NULL, 0);
return;
}
/* Mark the file as OWNERID_SHARED, if the file is shareable */
if((sinfo->ownerid_len == strlen(OWNERID_SHARED_TAG)) &&
!memcmp(sinfo->ownerid, OWNERID_SHARED_TAG,
sinfo->ownerid_len)) {
code_sign_set_ownerid(cs_info, FILE_OWNERID_SHARED, NULL, 0);
return;
}
/* If this code is signed on the device, check whether it is DEBUG_ID */
if((path_type = MAY_LOCAL_CODE) &&
(sinfo->ownerid_len == strlen(OWNERID_DEBUG_TAG)) &&
!memcmp(sinfo->ownerid, OWNERID_DEBUG_TAG,
sinfo->ownerid_len)) {
code_sign_set_ownerid(cs_info, FILE_OWNERID_DEBUG, NULL, 0);
return;
}
/* Mark the file OWNERID_APP in other cases */
code_sign_set_ownerid(cs_info, FILE_OWNERID_APP,
sinfo->ownerid, sinfo->ownerid_len);
}
static struct cert_source *find_matched_source(const struct x509_certificate *signer, bool is_debug)
{
int block_type = is_debug ? DEBUG_BLOCK_CODE: RELEASE_BLOCK_CODE;
@@ -76,7 +114,8 @@ static struct cert_source *find_matched_source(const struct x509_certificate *si
return source;
}
void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len, int *ret)
void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len,
struct cs_info *cs_info, int *ret)
{
struct pkcs7_message *pkcs7;
struct pkcs7_signed_info *sinfo;
@@ -103,7 +142,7 @@ void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len, int *re
bool is_dev_mode = false;
// developer mode && developer proc
if (!strcmp(developer_mode_state(), DEVELOPER_STATUS_ON)) {
if (get_developer_mode_state() == STATE_ON) {
code_sign_log_info("developer mode on");
is_dev_mode = true;
}
@@ -157,6 +196,7 @@ void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len, int *re
}
if (cert_chain_depth_without_root == (source->max_path_depth - 1)) {
code_sign_log_info("cert subject and issuer trusted");
set_file_ownerid(cs_info, source->path_type, pkcs7->signed_infos);
*ret = source->path_type;
goto exit;
} else {
+4 -2
View File
@@ -6,10 +6,12 @@
#ifndef _VERIFY_CERT_CHAIN_H
#define _VERIFY_CERT_CHAIN_H
#include <linux/xpm_types.h>
/*
* verify_cert_chain.c
*/
void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len, int *ret);
void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len,
struct cs_info *cs_info, int *ret);
#endif /* _VERIFY_CERT_CHAIN_H */
Executable → Regular
+2 -1
View File
@@ -9,6 +9,7 @@ menu "Executable permission manager"
config SECURITY_XPM
def_bool $(success, $(srctree)/scripts/ohos-check-dir.sh $(srctree)/security/xpm)
depends on 64BIT
depends on SECURITY_CODE_SIGN
help
The Executable Permission Manager(XPM) control process execution
by inserting control poliy into the security hook list, such as execv,
@@ -22,7 +23,7 @@ config DSMM_DEVELOPER_ENABLE
help
This option should only be enabled for the device support developer
mode feature. But whether or not developer mode is enabled on the
device ultimately depends on the developer_mode valude in cmdline.
device ultimately depends on the developer_mode string in cmdline.
config SECURITY_XPM_DEBUG
bool "Enables excutable permission manager debug mode"
Executable → Regular
+10 -5
View File
@@ -6,22 +6,27 @@
#
obj-$(CONFIG_SECURITY_XPM) += \
core/xpm_common.o \
core/xpm_module.o \
core/xpm_misc.o \
core/xpm_hck.o \
core/xpm_misc_device.o \
core/xpm_hck_hooks.o \
core/xpm_security_hooks.o \
core/xpm_report.o \
core/dsmm_developer.o \
validator/elf_code_segment_info.o \
validator/exec_signature_info.o
validator/exec_signature_info.o \
developer/dsmm_developer.o
obj-$(CONFIG_SECURITY_XPM_DEBUG) += \
core/xpm_debugfs.o
ccflags-$(CONFIG_SECURITY_XPM) += \
-I$(srctree)/security/xpm/include \
-I$(srctree)/security/xpm/core \
-I$(srctree)/security/xpm/validator \
-I$(srctree)/security/xpm/developer \
-I$(srctree)/security/selinux/include \
-I$(srctree)/security/selinux \
-I$(srctree)/fs \
-I$(srctree)/fs/verity \
-I$(srctree)/fs/code_sign
$(addprefix $(obj)/,$(obj-y)): $(obj)/flask.h
+11
View File
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include "xpm_common.h"
bool xpm_is_anonymous_vma(struct vm_area_struct *vma)
{
return vma_is_anonymous(vma) || vma_is_shmem(vma);
}
+23
View File
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_COMMON_H
#define _XPM_COMMON_H
#include <linux/mm.h>
#include <linux/sched.h>
/**
* xpm_is_anonymous_vma - Determine whether vma is anonymous.
*
* @vma: Pointer to "struct vm_area_struct" which need to be determined.
*
* Returns true on anonymunt, 0 on permissive mode.
*
* NOTE: shemem also been treated as anonymous vma.
*/
bool xpm_is_anonymous_vma(struct vm_area_struct *vma);
#endif /* _XPM_COMMON_H */
Executable → Regular
+5 -7
View File
@@ -4,19 +4,17 @@
*/
#include <linux/debugfs.h>
#include "xpm_log.h"
#include "xpm_hck.h"
#include "xpm_debugfs.h"
#define XPM_PERMISSIVE_MODE 0
#define XPM_ENFORCE_MODE 1
#include "xpm_debugfs.h"
#include "xpm_hck_hooks.h"
#include "xpm_log.h"
static struct dentry *xpm_dir;
static uint8_t xpm_mode = XPM_PERMISSIVE_MODE;
bool xpm_is_permissve_mode(void)
int xpm_ret(int ret)
{
return xpm_mode == XPM_PERMISSIVE_MODE;
return xpm_mode == XPM_ENFORCE_MODE ? ret : 0;
}
int xpm_debugfs_init(void)
+13 -3
View File
@@ -5,11 +5,21 @@
#ifndef _XPM_DEBUGFS_H
#define XPM_PERMISSIVE_MODE 0
#define XPM_ENFORCE_MODE 1
#ifdef CONFIG_SECURITY_XPM_DEBUG
int xpm_debugfs_init(void);
void xpm_debugfs_exit(void);
bool xpm_is_permissve_mode(void);
/**
* xpm_ret - Return value adapted to xpm enforce and permissive modes.
*
* @ret: Return value.
*
* Returns ret on enforce mode, 0 on permissive mode.
*/
int xpm_ret(int ret);
#else
static inline int xpm_debugfs_init(void)
{
@@ -20,9 +30,9 @@ static inline void xpm_debugfs_exit(void)
{
}
static inline bool xpm_is_permissve_mode(void)
static inline int xpm_ret(int ret)
{
return true;
return XPM_PERMISSIVE_MODE;
}
#endif
-385
View File
@@ -1,385 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*/
#include <asm/page.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/mman.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include <linux/sched/mm.h>
#include <linux/hck/lite_hck_xpm.h>
#include <linux/fsverity.h>
#include "avc.h"
#include "objsec.h"
#include "xpm_hck.h"
#include "xpm_log.h"
#include "xpm_report.h"
#include "xpm_debugfs.h"
#include "exec_signature_info.h"
static int xpm_value(int value)
{
return xpm_is_permissve_mode() ? 0 : value;
}
static bool xpm_is_anonymous_vma(struct vm_area_struct *vma)
{
return vma_is_anonymous(vma) || vma_is_shmem(vma);
}
static int xpm_avc_has_perm(u16 tclass, u32 requested)
{
struct av_decision avd;
u32 sid = current_sid();
int rc, rc2;
rc = avc_has_perm_noaudit(&selinux_state, sid, sid, tclass, requested,
AVC_STRICT, &avd);
rc2 = avc_audit(&selinux_state, sid, sid, tclass, requested, &avd, rc,
NULL, AVC_STRICT);
if (rc2)
return rc2;
return rc;
}
static int xpm_validate_signature(struct vm_area_struct *vma,
struct exec_file_signature_info *info)
{
unsigned long verified_data_end, vm_addr_end;
const struct inode *inode = (const struct inode *)info->inode;
if (IS_ERR_OR_NULL(info))
return xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_NO_SIGN);
if(!exec_file_signature_is_fs_verity(info))
return 0;
vm_addr_end = (vma->vm_pgoff << PAGE_SHIFT)
+ (vma->vm_end - vma->vm_start);
verified_data_end = PAGE_ALIGN(fsverity_get_verified_data_size(inode));
if (verified_data_end < vm_addr_end) {
xpm_log_error("data is out of verified data size.");
return -EPERM;
}
return 0;
}
static int xpm_check_code_segment(bool is_exec, struct vm_area_struct *vma,
struct exec_file_signature_info *info)
{
int i;
unsigned long vm_addr_start, vm_addr_end;
unsigned long seg_addr_start, seg_addr_end;
struct exec_segment_info *segments = info->code_segments;
if (!is_exec)
return 0;
if (!segments) {
xpm_log_error("code segments is NULL");
return -EINVAL;
}
vm_addr_start = vma->vm_pgoff << PAGE_SHIFT;
vm_addr_end = vm_addr_start + (vma->vm_end - vma->vm_start);
for (i = 0; i < info->code_segment_count; i++) {
seg_addr_start = ALIGN_DOWN(segments[i].file_offset, PAGE_SIZE);
seg_addr_end = PAGE_ALIGN(segments[i].file_offset +
segments[i].size);
if ((vm_addr_start >= seg_addr_start) &&
(vm_addr_end <= seg_addr_end))
return 0;
}
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;
bool is_exec;
struct exec_file_signature_info *info = NULL;
/* vma is non-executable or mmap in xpm region just return */
is_exec = !xpm_is_anonymous_vma(vma) && (prot & PROT_EXEC);
if (!((vma->vm_flags & VM_XPM) || is_exec))
return 0;
/* 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_check_signature_error(vma->vm_file, ret);
report_file_event(TYPE_FORMAT_UNDEF, vma->vm_file);
return ret;
}
ret = xpm_validate_signature(vma, info);
if (ret) {
xpm_log_error("xpm validate signature info failed");
report_mmap_event(TYPE_SIGN_INVALID, vma, is_exec, prot);
goto exit;
}
ret = xpm_check_code_segment(is_exec, vma, info);
if (ret) {
xpm_log_error("xpm check executable vma mmap code segment failed");
report_mmap_event(TYPE_DATA_MMAP_CODE, vma, is_exec, prot);
goto exit;
}
exit:
put_exec_file_signature_info(info);
return ret;
}
static int xpm_check_prot(struct vm_area_struct *vma, unsigned long prot)
{
int ret;
bool is_anon;
is_anon = xpm_is_anonymous_vma(vma);
if ((vma->vm_flags & VM_XPM) && (is_anon || (prot & PROT_WRITE) ||
(prot & PROT_EXEC))) {
xpm_log_error("xpm region mmap not allow anonymous/exec/write permission");
return -EPERM;
}
/* anonymous executable permission need controled by selinux */
if (is_anon && (prot & PROT_EXEC)) {
ret = xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_ANON_MEM);
if (ret) {
xpm_log_error("anonymous mmap not allow exec permission");
report_mmap_event(TYPE_ANON_EXEC, vma, TYPE_ANON, prot);
return -EPERM;
}
}
if (!is_anon && (prot & PROT_WRITE) && (prot & PROT_EXEC)) {
xpm_log_error("file mmap not allow write & exec permission");
return -EPERM;
}
return 0;
}
static int xpm_common_check(struct vm_area_struct *vma, unsigned long prot)
{
int ret;
do {
ret = xpm_check_prot(vma, prot);
if (ret)
break;
ret = xpm_check_signature(vma, prot);
} while (0);
return xpm_value(ret);
}
static int xpm_mmap_check(struct vm_area_struct *vma)
{
return xpm_common_check(vma, vma->vm_flags);
}
static int xpm_mprotect_check(struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
{
(void)reqprot;
return xpm_common_check(vma, prot);
}
void xpm_delete_cache_node(struct inode *file_node)
{
delete_exec_file_signature_info(file_node);
}
static void xpm_region_outer(unsigned long addr_start, unsigned long addr_end,
unsigned long flags, bool *ret)
{
struct mm_struct *mm = current->mm;
if (!mm)
return;
/* Already in xpm region, just return without judge */
if (flags & VM_UNMAPPED_AREA_XPM)
return;
*ret = ((addr_start >= mm->xpm_region.addr_end) ||
(addr_end <= mm->xpm_region.addr_start));
}
void xpm_get_unmapped_area(unsigned long addr, unsigned long len,
unsigned long map_flags, unsigned long unmapped_flags,
unsigned long *ret)
{
struct vm_unmapped_area_info info;
struct mm_struct *mm = current->mm;
if (!mm)
return;
if ((mm->xpm_region.addr_start == 0) && (mm->xpm_region.addr_end == 0))
return;
if ((map_flags & MAP_FIXED) && !(addr >= mm->xpm_region.addr_end ||
addr + len <= mm->xpm_region.addr_start)) {
xpm_log_error("xpm region not allow mmap with MAP_FIXED");
*ret = -EFAULT;
return;
}
if (map_flags & MAP_XPM) {
if (addr) {
xpm_log_error("xpm region not allow specify addr");
*ret = -EPERM;
return;
}
info.flags = VM_UNMAPPED_AREA_XPM | unmapped_flags;
info.length = len;
info.low_limit = mm->xpm_region.addr_start;
info.high_limit = mm->xpm_region.addr_end;
info.align_mask = 0;
info.align_offset = 0;
*ret = vm_unmapped_area(&info);
}
}
/*
* A xpm readonly region is an area where any page mapped
* will be marked with XPMReadonly.
* Return 1 if a region is readonly, otherwise, return 0.
*/
static bool is_xpm_readonly_region(struct vm_area_struct *vma)
{
/* 1. xpm region */
if (vma->vm_flags & VM_XPM)
return true;
/* 2. !anonymous && executable */
if (!xpm_is_anonymous_vma(vma) && (vma->vm_flags & VM_EXEC))
return true;
return false;
}
void xpm_integrity_check(struct vm_area_struct *vma, unsigned int vflags,
unsigned long addr, struct page *page, vm_fault_t *ret)
{
if (!page)
return;
/* integrity violation: write a readonly page */
if ((vflags & FAULT_FLAG_WRITE) && (vma->vm_flags & VM_WRITE) &&
PageXPMReadonly(page)) {
report_integrity_event(TYPE_INTEGRITY_RO, vma, page);
*ret = xpm_value(VM_FAULT_SIGSEGV);
return;
}
/* integrity violation: execute a writetained page */
if (PageXPMWritetainted(page) && is_xpm_readonly_region(vma)) {
report_integrity_event(TYPE_INTEGRITY_WT, vma, page);
*ret = xpm_value(VM_FAULT_SIGSEGV);
return;
}
}
void xpm_integrity_update(struct vm_area_struct *vma, unsigned int vflags,
struct page *page)
{
/* set writetainted only if a real write occurred */
if ((vflags & FAULT_FLAG_WRITE) && (vma->vm_flags & VM_WRITE) &&
!PageXPMWritetainted(page)) {
SetPageXPMWritetainted(page);
return;
}
/* set xpm readonly flag */
if (is_xpm_readonly_region(vma) && !PageXPMReadonly(page))
SetPageXPMReadonly(page);
}
void xpm_integrity_validate(struct vm_area_struct *vma, unsigned int vflags,
unsigned long addr, struct page *page, vm_fault_t *ret)
{
if (!page)
return;
xpm_integrity_check(vma, vflags, addr, page, ret);
if (!*ret)
xpm_integrity_update(vma, vflags, page);
}
/*
* check the integrity of these two pages, return true if equal,
* otherwise false
*/
void xpm_integrity_equal(struct page *page, struct page *kpage, bool *ret)
{
if (!page || !kpage)
return;
*ret = ((PageXPMWritetainted(page) == PageXPMWritetainted(kpage)) &&
(PageXPMReadonly(page) == PageXPMReadonly(kpage)));
}
static struct security_hook_list xpm_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(mmap_region, xpm_mmap_check),
LSM_HOOK_INIT(file_mprotect, xpm_mprotect_check),
};
void xpm_register_xpm_hooks(void)
{
security_add_hooks(xpm_hooks, ARRAY_SIZE(xpm_hooks), "xpm");
}
void xpm_register_hck_hooks(void)
{
REGISTER_HCK_LITE_HOOK(xpm_delete_cache_node_lhck,
xpm_delete_cache_node);
REGISTER_HCK_LITE_HOOK(xpm_region_outer_lhck, xpm_region_outer);
REGISTER_HCK_LITE_HOOK(xpm_get_unmapped_area_lhck,
xpm_get_unmapped_area);
/* xpm integrity */
REGISTER_HCK_LITE_HOOK(xpm_integrity_equal_lhck, xpm_integrity_equal);
REGISTER_HCK_LITE_HOOK(xpm_integrity_check_lhck, xpm_integrity_check);
REGISTER_HCK_LITE_HOOK(xpm_integrity_update_lhck, xpm_integrity_update);
REGISTER_HCK_LITE_HOOK(xpm_integrity_validate_lhck,
xpm_integrity_validate);
}
+180
View File
@@ -0,0 +1,180 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
*/
#include <asm/page.h>
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/hck/lite_hck_xpm.h>
#include <linux/mman.h>
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include "exec_signature_info.h"
#include "xpm_common.h"
#include "xpm_debugfs.h"
#include "xpm_hck_hooks.h"
#include "xpm_log.h"
#include "xpm_report.h"
static void xpm_delete_cache_node(struct inode *file_node)
{
delete_exec_file_signature_info(file_node);
}
static void xpm_region_outer(unsigned long addr_start, unsigned long addr_end,
unsigned long flags, bool *ret)
{
struct mm_struct *mm = current->mm;
if (!mm)
return;
/*
* VM_UNMAPPED_AREA_XPM identifies the address to allocated in the
* xpm_region, just ignore.
*/
if (flags & VM_UNMAPPED_AREA_XPM)
return;
*ret = ((addr_start >= mm->xpm_region.addr_end) ||
(addr_end <= mm->xpm_region.addr_start));
}
void xpm_get_unmapped_area(unsigned long addr, unsigned long len,
unsigned long map_flags, unsigned long unmapped_flags,
unsigned long *ret)
{
struct vm_unmapped_area_info info;
struct mm_struct *mm = current->mm;
if (!mm)
return;
if ((mm->xpm_region.addr_start == 0) && (mm->xpm_region.addr_end == 0))
return;
if ((map_flags & MAP_FIXED) && !(addr >= mm->xpm_region.addr_end ||
addr + len <= mm->xpm_region.addr_start)) {
xpm_log_error("xpm region not allow mmap with MAP_FIXED");
*ret = -EFAULT;
return;
}
if (map_flags & MAP_XPM) {
if (addr) {
xpm_log_error("xpm region not allow specify addr");
*ret = -EPERM;
return;
}
info.flags = VM_UNMAPPED_AREA_XPM | unmapped_flags;
info.length = len;
info.low_limit = mm->xpm_region.addr_start;
info.high_limit = mm->xpm_region.addr_end;
info.align_mask = 0;
info.align_offset = 0;
*ret = vm_unmapped_area(&info);
}
}
/*
* A xpm readonly region is an area where any page mapped
* will be marked with XPMReadonly.
*
* Return 1 if a region is readonly, otherwise, return 0.
*/
static bool is_xpm_readonly_region(struct vm_area_struct *vma)
{
/* xpm region */
if (vma->vm_flags & VM_XPM)
return true;
/* !anonymous && executable */
if (!xpm_is_anonymous_vma(vma) && (vma->vm_flags & VM_EXEC))
return true;
return false;
}
void xpm_integrity_check(struct vm_area_struct *vma, unsigned int vflags,
unsigned long addr, struct page *page, vm_fault_t *ret)
{
if (!page)
return;
/* integrity violation: write a readonly page */
if ((vflags & FAULT_FLAG_WRITE) && (vma->vm_flags & VM_WRITE) &&
PageXPMReadonly(page)) {
report_integrity_event(INTEGRITY_RO, vma, page);
*ret = xpm_ret(VM_FAULT_SIGSEGV);
return;
}
/* integrity violation: execute a writetained page */
if (PageXPMWritetainted(page) && is_xpm_readonly_region(vma)) {
report_integrity_event(INTEGRITY_WT, vma, page);
*ret = xpm_ret(VM_FAULT_SIGSEGV);
return;
}
}
void xpm_integrity_update(struct vm_area_struct *vma, unsigned int vflags,
struct page *page)
{
/* set writetainted only if a real write occurred */
if ((vflags & FAULT_FLAG_WRITE) && (vma->vm_flags & VM_WRITE) &&
!PageXPMWritetainted(page)) {
SetPageXPMWritetainted(page);
return;
}
/* set xpm readonly flag */
if (is_xpm_readonly_region(vma) && !PageXPMReadonly(page))
SetPageXPMReadonly(page);
}
void xpm_integrity_validate(struct vm_area_struct *vma, unsigned int vflags,
unsigned long addr, struct page *page, vm_fault_t *ret)
{
if (!page)
return;
xpm_integrity_check(vma, vflags, addr, page, ret);
if (!*ret)
xpm_integrity_update(vma, vflags, page);
}
/*
* check the integrity of these two pages.
*
* Return true if equal, otherwise false.
*/
void xpm_integrity_equal(struct page *page, struct page *kpage, bool *ret)
{
if (!page || !kpage)
return;
*ret = ((PageXPMWritetainted(page) == PageXPMWritetainted(kpage)) &&
(PageXPMReadonly(page) == PageXPMReadonly(kpage)));
}
void xpm_register_hck_hooks(void)
{
REGISTER_HCK_LITE_HOOK(xpm_delete_cache_node_lhck,
xpm_delete_cache_node);
REGISTER_HCK_LITE_HOOK(xpm_region_outer_lhck, xpm_region_outer);
REGISTER_HCK_LITE_HOOK(xpm_get_unmapped_area_lhck,
xpm_get_unmapped_area);
/* xpm integrity */
REGISTER_HCK_LITE_HOOK(xpm_integrity_equal_lhck, xpm_integrity_equal);
REGISTER_HCK_LITE_HOOK(xpm_integrity_check_lhck, xpm_integrity_check);
REGISTER_HCK_LITE_HOOK(xpm_integrity_update_lhck, xpm_integrity_update);
REGISTER_HCK_LITE_HOOK(xpm_integrity_validate_lhck,
xpm_integrity_validate);
}
@@ -3,13 +3,9 @@
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_HCK_H
#define _XPM_HCK_H
void set_xpm_mode(uint8_t mode);
void xpm_register_xpm_hooks(void);
#ifndef _XPM_HCK_HOOKS_H
#define _XPM_HCK_HOOKS_H
void xpm_register_hck_hooks(void);
#endif /* _XPM_HCK_H */
#endif /* _XPM_HCK_HOOKS_H */
@@ -6,8 +6,6 @@
#ifndef _XPM_LOG_H
#define _XPM_LOG_H
#define XPM_CHECK_FAILED (-1024)
#define XPM_TAG "xpm_kernel"
#define XPM_INFO_TAG "I"
#define XPM_ERROR_TAG "E"
+65 -34
View File
@@ -3,64 +3,103 @@
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include "xpm_misc.h"
#include <linux/code_sign.h>
#include <linux/compat.h>
#include <linux/file.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/file.h>
#include <linux/compat.h>
#include <linux/mm_types.h>
#include <linux/miscdevice.h>
#include <linux/xpm_types.h>
#include "code_sign_ext.h"
#include "xpm_log.h"
#include "xpm_misc_device.h"
#include "xpm_report.h"
#define XPM_SET_REGION _IOW('x', 0x01, struct xpm_region_info)
#define XPM_SET_REGION _IOW('x', 0x01, struct xpm_config)
#define XPM_SET_OWNERID _IOW('x', 0x02, struct xpm_config)
static int xpm_set_region(unsigned long addr_base, unsigned long length)
static int xpm_set_region(struct xpm_config *config)
{
int ret = 0;
unsigned long addr;
uint64_t addr;
struct mm_struct *mm = current->mm;
if (!mm)
return -EINVAL;
if (mmap_write_lock_killable(mm))
return -EINTR;
if ((mm->xpm_region.addr_start != 0) ||
(mm->xpm_region.addr_end != 0)) {
xpm_log_info("xpm region has been set");
goto exit;
return 0;
}
addr = get_unmapped_area(NULL, addr_base, length, 0, 0);
if (IS_ERR_VALUE(addr) || (ULONG_MAX - addr_base < length)) {
addr = get_unmapped_area(NULL, config->region_addr,
config->region_length, 0, 0);
if (IS_ERR_VALUE(addr) || (ULLONG_MAX - addr < config->region_length)) {
xpm_log_error("xpm get unmmaped area failed");
ret = -EINVAL;
goto exit;
return -EINVAL;
}
if (mmap_write_lock_killable(mm))
return -EINTR;
mm->xpm_region.addr_start = addr;
mm->xpm_region.addr_end = addr + length;
exit:
mm->xpm_region.addr_end = addr + config->region_length;
mmap_write_unlock(mm);
return ret;
return 0;
}
static int xpm_set_ownerid(struct xpm_config *config)
{
struct mm_struct *mm = current->mm;
if (!mm)
return -EINVAL;
if (config->id_type >= PROCESS_OWNERID_MAX) {
xpm_log_error("input ownerid type is invalid");
return -EINVAL;
}
#ifndef CONFIG_SECURITY_XPM_DEBUG
if ((mm->pcs_info.id_type == PROCESS_OWNERID_APP) ||
mm->pcs_info.id_type == PROCESS_OWNERID_DEBUG) {
xpm_log_info("process ownerid has been set");
return 0;
}
#endif
if (config->ownerid[MAX_OWNERID_LEN - 1] != '\0') {
xpm_log_error("input ownerid string is invalid");
return -EINVAL;
}
if (mmap_write_lock_killable(mm))
return -EINTR;
code_sign_set_ownerid(&mm->pcs_info, config->id_type,
config->ownerid, strlen(config->ownerid));
mmap_write_unlock(mm);
return 0;
}
static long xpm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
struct xpm_region_info info = {0};
struct xpm_config config = {0};
if (unlikely(copy_from_user(&info, (void __user *)(uintptr_t)arg,
sizeof(struct xpm_region_info))))
if (unlikely(copy_from_user(&config, u64_to_user_ptr((uint64_t)arg),
sizeof(struct xpm_config))))
return -EFAULT;
switch (cmd) {
case XPM_SET_REGION:
ret = xpm_set_region(info.addr_base, info.length);
ret = xpm_set_region(&config);
break;
case XPM_SET_OWNERID:
ret = xpm_set_ownerid(&config);
break;
default:
xpm_log_error("xpm ioctl cmd error, cmd = %d", cmd);
@@ -71,14 +110,6 @@ static long xpm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return ret;
}
#ifdef CONFIG_COMPAT
static long xpm_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return 0;
}
#endif
static int xpm_open(struct inode *inode, struct file *file)
{
return 0;
@@ -95,7 +126,7 @@ static const struct file_operations xpm_fops = {
.release = xpm_release,
.unlocked_ioctl = xpm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = xpm_compat_ioctl,
.compat_ioctl = xpm_ioctl,
#endif
};
+24
View File
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_MISC_DEVICE_H
#define _XPM_MISC_DEVICE_H
#include <linux/xpm_types.h>
#define MAX_OWNERID_LEN 64
struct xpm_config {
uint64_t region_addr;
uint64_t region_length;
uint32_t id_type;
char ownerid[MAX_OWNERID_LEN];
};
int xpm_register_misc_device(void);
void xpm_deregister_misc_device(void);
#endif /* _XPM_MISC_DEVICE_H */
Executable → Regular
+10 -8
View File
@@ -7,12 +7,14 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include "xpm_log.h"
#include "xpm_hck.h"
#include "xpm_misc.h"
#include "xpm_report.h"
#include "xpm_debugfs.h"
#include "dsmm_developer.h"
#include "xpm_debugfs.h"
#include "xpm_hck_hooks.h"
#include "xpm_misc_device.h"
#include "xpm_security_hooks.h"
#include "xpm_report.h"
#include "xpm_log.h"
static int __init xpm_module_init(void)
{
@@ -21,7 +23,7 @@ static int __init xpm_module_init(void)
ret = xpm_register_misc_device();
if (ret) {
xpm_log_error("xpm register misc device failed, ret = %d", ret);
report_init_event(TYPE_DEVICEFS_UNINIT);
report_init_event(DEVICEFS_UNINIT);
return ret;
}
@@ -29,11 +31,11 @@ static int __init xpm_module_init(void)
if (ret) {
xpm_log_error("xpm init debugfs failed, ret = %d", ret);
xpm_deregister_misc_device();
report_init_event(TYPE_DEBUGFS_UNINIT);
report_init_event(DEBUGFS_UNINIT);
return ret;
}
xpm_register_xpm_hooks();
xpm_register_security_hooks();
xpm_register_hck_hooks();
dsmm_developer_proc_create();
+184 -148
View File
@@ -3,18 +3,30 @@
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <linux/mm.h>
#include <linux/rmap.h>
#include <linux/mman.h>
#include <linux/fs.h>
#include <linux/xpm.h>
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/fsverity.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/rmap.h>
#include <linux/xpm.h>
#ifdef CONFIG_HW_KERNEL_SG
#include <security/security_guard_collect.h>
#endif
#include "code_sign_ext.h"
#include "fsverity_private.h"
#include "xpm_log.h"
#include "xpm_report.h"
#define PROT_MASK (PROT_EXEC | PROT_READ | PROT_WRITE)
static char *code_type_tbl[] = {
[TYPE_ABC] = "ABC",
[TYPE_ELF] = "ELF",
[TYPE_ANON] = "ANON"
};
#ifndef CONFIG_HW_KERNEL_SG
typedef struct {
unsigned long event_id;
@@ -22,43 +34,51 @@ typedef struct {
unsigned int content_len;
char content[0];
} event_info;
unsigned int report_security_info(const event_info *event)
{
xpm_log_info("%d: %s", event->event_id, event->content);
return 0;
}
#endif
static char *xpm_get_filename(struct xpm_event_param *param, char *buf, int len)
unsigned int xpm_report_security_info(const event_info *event)
{
char *filename = NULL;
struct file *file = NULL;
xpm_log_error("%d: %s", event->event_id, event->content);
if (param->file)
file = param->file;
else if (param->vma && param->vma->vm_file)
file = param->vma->vm_file;
else
return NULL;
filename = d_absolute_path(&file->f_path, buf, len);
if (IS_ERR(filename)) {
xpm_log_error("xpm get absolute path failed");
return NULL;
}
return filename;
#ifdef CONFIG_HW_KERNEL_SG
return report_security_info(event);
#else
return 0;
#endif
}
static int set_init_content(struct xpm_event_param *param,
static void xpm_set_filename(struct file *file, struct xpm_report_info *info)
{
char *filename = NULL;
char *buffer = NULL;
if (!file)
return;
buffer = kzalloc(sizeof(info->filename), GFP_ATOMIC);
if (!buffer) {
xpm_log_error("alloc filename buffer failed");
return;
}
filename = file_path(file, buffer, sizeof(info->filename) - 1);
if (IS_ERR(filename)) {
xpm_log_error("xpm set file path failed");
} else {
strcpy(info->filename, filename);
}
kfree(buffer);
}
static int set_init_content(struct xpm_report_info *info,
uint8_t *content, uint32_t content_len)
{
int len;
len = snprintf(content, content_len,
"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)" }",
param->event_type, param->timestamp);
info->event_type, info->timestamp);
if (len < 0 || len > content_len) {
xpm_log_error("snprintf init content failed");
@@ -68,32 +88,24 @@ static int set_init_content(struct xpm_event_param *param,
return 0;
}
#define PROT_MASK (PROT_EXEC | PROT_READ | PROT_WRITE)
const static char *code_type[] = {
[TYPE_ABC] = "ABC",
[TYPE_ELF] = "ELF",
[TYPE_ANON] = "ANON"
};
static int set_mmap_content(struct xpm_event_param *param, uint8_t *content,
static int set_mmap_content(struct xpm_report_info *info, uint8_t *content,
uint32_t content_len)
{
int len;
if (!param->vma) {
xpm_log_error("input vma is NULL");
return -EINVAL;
}
len = snprintf(content, content_len,
"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)", "
JVAL_PAIR(pid, %u)", "JSTR_PAIR(filename, %s)", "
JSTR_PAIR(code_type, %s)", "JVAL_PAIR(prot, %lu)","
JVAL_PAIR(pgoff, %lu)", "JVAL_PAIR(size, %lu)" }",
param->event_type, param->timestamp, param->pid,
param->filename ? param->filename : "",
code_type[param->code], param->prot & PROT_MASK,
param->vma->vm_pgoff,
param->vma->vm_end - param->vma->vm_start);
"{ "JSTR_PAIR(event_type, %s)", "JSTR_PAIR(code_type, %s)", "
JVAL_PAIR(pid, %u)", "JSTR_PAIR(comm, %s)", "
JSTR_PAIR(filename, %s)", "JVAL_PAIR(vm_prot, %lu)","
JVAL_PAIR(vm_pgoff, %lu)", "JVAL_PAIR(vm_size, %lu)", "
JVAL_PAIR(p_id_type, %u)", "JSTR_PAIR(p_ownerid, %u)", "
JVAL_PAIR(f_id_type, %u)", "JSTR_PAIR(f_ownerid, %u)", "
JSTR_PAIR(timestamp, %llu)" }",
info->event_type, info->code_type, info->pid, info->comm,
info->filename, info->vm_prot, info->vm_pgoff, info->vm_size,
info->pcs_info.id_type, info->pcs_info.ownerid,
info->fcs_info.id_type, info->fcs_info.ownerid,
info->timestamp);
if (len < 0 || len > content_len) {
xpm_log_error("snprintf code mmap content failed");
@@ -103,16 +115,17 @@ static int set_mmap_content(struct xpm_event_param *param, uint8_t *content,
return 0;
}
static int set_file_content(struct xpm_event_param *param,
static int set_file_content(struct xpm_report_info *info,
uint8_t *content, uint32_t content_len)
{
int len;
len = snprintf(content, content_len,
"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)", "
JVAL_PAIR(pid, %u)", "JSTR_PAIR(filename, %s)" }",
param->event_type, param->timestamp, param->pid,
param->filename ? param->filename : "");
"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(pid, %u)", "
JSTR_PAIR(comm, %s)", "JSTR_PAIR(filename, %s)", "
JVAL_PAIR(timestap, %llu)" }",
info->event_type, info->pid, info->comm,
info->filename, info->timestamp);
if (len < 0 || len > content_len) {
xpm_log_error("snprintf file format content failed");
@@ -122,28 +135,19 @@ static int set_file_content(struct xpm_event_param *param,
return 0;
}
static int set_integrity_content(struct xpm_event_param *param,
static int set_integrity_content(struct xpm_report_info *info,
uint8_t *content, uint32_t content_len)
{
int len;
char *page_type;
if (!param->vma || !param->page) {
xpm_log_error("input vma or page is NULL");
return -EINVAL;
}
page_type = PageKsm(param->page) ?
"[ksm]" : PageAnon(param->page) ? "[anon]" : "[file]";
len = snprintf(content, content_len,
"{ " JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)", "
JVAL_PAIR(pid, %u)","JSTR_PAIR(page_type, %s)", "
JSTR_PAIR(filename, %s)", "JVAL_PAIR(page_index, %lu)","
JVAL_PAIR(page_prot, %lu)" }",
param->event_type, param->timestamp, param->pid, page_type,
param->filename ? param->filename : "", param->page->index,
param->vma->vm_page_prot.pgprot & PROT_MASK);
"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(pid, %u)", "
JSTR_PAIR(comm, %s)", "JSTR_PAIR(filename, %s)", "
JSTR_PAIR(page_type, %s)", "JVAL_PAIR(page_index, %lu)", "
JVAL_PAIR(vm_pgprot, %lu)", "JVAL_PAIR(timestamp, %llu)" }",
info->event_type, info->pid, info->comm, info->filename,
info->page_type, info->page_index, info->vm_pgprot,
info->timestamp);
if (len < 0 || len > content_len) {
xpm_log_error("snprintf init integrity failed");
@@ -153,120 +157,152 @@ static int set_integrity_content(struct xpm_event_param *param,
return 0;
}
static const struct xpm_event_info xpm_event[] = {
[TYPE_DEVICEFS_UNINIT] = { "devicefs uninitialized",
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",
EVENT_MMAP, set_file_content },
[TYPE_SIGN_INVALID] = { "invalid signature",
EVENT_MMAP, set_mmap_content },
[TYPE_DATA_MMAP_CODE] = { "data mmap code",
EVENT_MMAP, set_mmap_content },
[TYPE_INTEGRITY_RO] = { "code tampered",
EVENT_INTEGRITY, set_integrity_content },
[TYPE_INTEGRITY_WT] = { "data executed",
EVENT_INTEGRITY, set_integrity_content },
};
static int report_event_inner(enum xpm_event_type type,
struct xpm_event_param *param, event_info *event)
static void xpm_set_report_info(struct xpm_report_param *param,
struct xpm_report_info *info)
{
int ret;
struct fsverity_info *vi = NULL;
struct file *file = param->file;
struct mm_struct *mm = current->mm;
ret = xpm_event[type].set_content(param, event->content,
MAX_CONTENT_LEN);
if (ret) {
xpm_log_error("type [%d] set content failed", type);
return ret;
}
event->content_len = strlen(event->content);
event->event_id = xpm_event[type].event_id;
event->version = XPM_EVENT_VERSION;
info->event_type = param->event_type;
info->code_type = code_type_tbl[param->code_type];
ret = report_security_info(event);
if (ret) {
xpm_log_error("type [%d] report security info failed", type);
return ret;
info->pid = current->pid;
memcpy(info->comm, current->comm, TASK_COMM_LEN);
if (mm) {
info->pcs_info.id_type = mm->pcs_info.id_type;
info->pcs_info.ownerid = mm->pcs_info.ownerid;
}
return 0;
info->vm_prot = param->vm_prot & PROT_MASK;
if (param->vma) {
info->vm_pgoff = param->vma->vm_pgoff;
info->vm_size = param->vma->vm_end - param->vma->vm_start;
info->vm_pgprot = param->vma->vm_page_prot.pgprot & PROT_MASK;
file = param->vma->vm_file;
}
if (param->page) {
info->page_type = PageKsm(param->page) ?
"[ksm]" : PageAnon(param->page) ? "[anon]" : "[file]";
info->page_index = param->page->index;
}
/* init file ownerid type SYSTEM */
info->fcs_info.id_type = FILE_OWNERID_SYSTEM;
if (file) {
xpm_set_filename(file, info);
vi = fsverity_get_info(file_inode(file));
if (vi) {
info->fcs_info.id_type = vi->fcs_info.id_type;
info->fcs_info.ownerid = vi->fcs_info.ownerid;
}
}
info->timestamp = ktime_get_real_seconds();
}
static int xpm_report_event(enum xpm_event_type type,
struct xpm_event_param *param)
static int xpm_report_event(struct xpm_report_param *param)
{
int ret;
event_info *sg_event;
char *buf;
event_info *event = NULL;
struct xpm_report_info *info = NULL;
if (!(xpm_event[type].set_content)) {
xpm_log_error("type [%d] set content func invalid", type);
if (!param->event_type) {
xpm_log_error("xpm event type is NULL");
return -EINVAL;
}
sg_event = kzalloc(sizeof(event_info) + MAX_CONTENT_LEN, GFP_KERNEL);
if (!sg_event) {
info = kzalloc(sizeof(struct xpm_report_info), GFP_ATOMIC);
if (!info) {
xpm_log_error("alloc xpm report info struct failed");
return -ENOMEM;
}
event = kzalloc(sizeof(event_info) + MAX_CONTENT_LEN, GFP_ATOMIC);
if (!event) {
xpm_log_error("alloc security guard event failed");
kfree(info);
return -ENOMEM;
}
buf = __getname();
if (!buf) {
xpm_log_error("alloc file name buf failed");
kfree(sg_event);
return -ENOMEM;
}
do {
event->version = XPM_EVENT_VERSION;
event->event_id = param->event_id;
param->event_type = xpm_event[type].event_type;
param->filename = xpm_get_filename(param, buf, PATH_MAX);
param->timestamp = ktime_get_real_seconds();
param->pid = current->pid;
/* set xpm report info from param */
xpm_set_report_info(param, info);
ret = param->set_content(info, event->content, MAX_CONTENT_LEN);
if (ret) {
xpm_log_error("type [%s] set content failed",
param->event_type);
break;
}
event->content_len = strlen(event->content);
ret = report_event_inner(type, param, sg_event);
ret = xpm_report_security_info(event);
if (ret) {
xpm_log_error("type [%s] report security info failed",
param->event_type);
break;
}
__putname(buf);
kfree(sg_event);
} while (0);
kfree(info);
kfree(event);
return ret;
}
void report_init_event(enum xpm_event_type type)
void report_init_event(char *event_type)
{
struct xpm_event_param param = {0};
struct xpm_report_param param = {0};
xpm_report_ratelimited(xpm_report_event, type, &param);
param.event_type = event_type;
param.event_id = EVENT_INIT;
param.set_content = &set_init_content;
xpm_report_ratelimited(xpm_report_event, &param);
}
void report_file_event(enum xpm_event_type type, struct file *file)
void report_file_event(char *event_type, struct file *file)
{
struct xpm_event_param param = {0};
struct xpm_report_param param = {0};
param.event_type = event_type;
param.event_id = EVENT_FILE;
param.file = file;
xpm_report_ratelimited(xpm_report_event, type, &param);
param.set_content = &set_file_content;
xpm_report_ratelimited(xpm_report_event, &param);
}
void report_mmap_event(enum xpm_event_type type, struct vm_area_struct *vma,
int code, int prot)
void report_mmap_event(char *event_type, enum xpm_code_type code_type,
struct vm_area_struct *vma, unsigned long vm_prot)
{
struct xpm_event_param param = {0};
struct xpm_report_param param = {0};
param.event_type = event_type;
param.event_id = EVENT_MMAP;
param.code_type = code_type;
param.vma = vma;
param.code = code;
param.prot = prot;
xpm_report_ratelimited(xpm_report_event, type, &param);
param.vm_prot = vm_prot;
param.set_content = &set_mmap_content;
xpm_report_ratelimited(xpm_report_event, &param);
}
void report_integrity_event(enum xpm_event_type type,
struct vm_area_struct *vma, struct page *page)
void report_integrity_event(char *event_type, struct vm_area_struct *vma,
struct page *page)
{
struct xpm_event_param param = {0};
struct xpm_report_param param = {0};
param.event_type = event_type;
param.event_id = EVENT_INTEGRITY;
param.vma = vma;
param.page = page;
xpm_report_ratelimited(xpm_report_event, type, &param);
param.set_content = &set_integrity_content;
xpm_report_ratelimited(xpm_report_event, &param);
}
+113
View File
@@ -0,0 +1,113 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_REPORT_H
#define _XPM_REPORT_H
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/xpm_types.h>
#define NULL_STR "NULL"
#define MAX_FILENAME_LEN 128
/* EVENT_INIT */
#define DEVICEFS_UNINIT "devicefs uninitialized"
#define DEBUGFS_UNINIT "debugfs uninitialized"
#define DM_DISABLE "dm-verity disable"
/* EVENT_FILE */
#define FORMAT_UNDEF "unkown file format"
/* EVENT_MMAP */
#define ANON_EXEC "anon executed"
#define GET_SIGN_FAIL "get signature info failed"
#define SIGN_INVALID "invalid signature"
#define DATA_MMAP_CODE "data mmap code"
#define OWNERID_INCONSISTENT "ownerid inconsistent"
/* EVENT_INTEGRITY */
#define INTEGRITY_RO "code tampered"
#define INTEGRITY_WT "data executed"
enum xpm_code_type {
TYPE_ABC = 0,
TYPE_ELF,
TYPE_ANON,
};
enum xpm_event_id {
EVENT_INIT = 1011009110,
EVENT_FILE = 1011009111,
EVENT_MMAP = 1011009112,
EVENT_INTEGRITY = 1011009113,
};
/* set of report info */
struct xpm_report_info {
char *event_type;
char *code_type;
pid_t pid;
char comm[TASK_COMM_LEN];
char filename[MAX_FILENAME_LEN + 1];
struct cs_info pcs_info;
struct cs_info fcs_info;
unsigned long vm_prot;
unsigned long vm_pgprot;
unsigned long vm_pgoff;
unsigned long vm_size;
char *page_type;
pgoff_t page_index;
ktime_t timestamp;
};
/* set of caller parameters */
struct xpm_report_param {
char *event_type;
enum xpm_event_id event_id;
enum xpm_code_type code_type;
struct vm_area_struct *vma;
unsigned long vm_prot;
struct page *page;
struct file *file;
int (*set_content)(struct xpm_report_info *info, uint8_t *content,
uint32_t content_len);
};
#define MAX_CONTENT_LEN 900
#define XPM_EVENT_VERSION 0
#ifndef CONFIG_SECURITY_XPM_DEBUG
#define xpm_report_ratelimited(func, fmt, ...) \
do { \
static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, \
DEFAULT_RATELIMIT_BURST); \
if (__ratelimit(&_rs)) \
func(fmt, ##__VA_ARGS__); \
} while (0)
#else
#define xpm_report_ratelimited(func, fmt, ...) \
func(fmt, ##__VA_ARGS__);
#endif
#define JSTR(val) "\""#val"\""
#define JVAL_PAIR(val, format) JSTR(val) ": " #format
#define JSTR_PAIR(val, format) JSTR(val) ": " JSTR(format)
void report_init_event(char *event_type);
void report_file_event(char *event_type, struct file *file);
void report_mmap_event(char *event_type, enum xpm_code_type code_type,
struct vm_area_struct *vma, unsigned long prot);
void report_integrity_event(char *event_type, struct vm_area_struct *vma,
struct page *page);
#endif /* _XPM_REPORT_H */
+373
View File
@@ -0,0 +1,373 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <linux/mman.h>
#include <linux/mm_types.h>
#include "avc.h"
#include "objsec.h"
#include "exec_signature_info.h"
#include "fsverity_private.h"
#include "code_sign_ext.h"
#include "xpm_common.h"
#include "xpm_debugfs.h"
#include "xpm_log.h"
#include "xpm_report.h"
#include "xpm_security_hooks.h"
enum ownerid_policy_type {
DENY = 0,
ALLOW,
CHECK,
};
static uint32_t ownerid_policy[PROCESS_OWNERID_MAX][FILE_OWNERID_MAX] __ro_after_init;
static void init_ownerid_policy(void)
{
ownerid_policy[PROCESS_OWNERID_SYSTEM][FILE_OWNERID_SYSTEM] = ALLOW;
ownerid_policy[PROCESS_OWNERID_APP][FILE_OWNERID_SYSTEM] = ALLOW;
ownerid_policy[PROCESS_OWNERID_APP][FILE_OWNERID_SHARED] = ALLOW;
ownerid_policy[PROCESS_OWNERID_APP][FILE_OWNERID_APP] = CHECK;
ownerid_policy[PROCESS_OWNERID_DEBUG][FILE_OWNERID_SYSTEM] = ALLOW;
ownerid_policy[PROCESS_OWNERID_DEBUG][FILE_OWNERID_SHARED] = ALLOW;
ownerid_policy[PROCESS_OWNERID_DEBUG][FILE_OWNERID_DEBUG] = ALLOW;
ownerid_policy[PROCESS_OWNERID_COMPAT][FILE_OWNERID_SYSTEM] = ALLOW;
ownerid_policy[PROCESS_OWNERID_COMPAT][FILE_OWNERID_COMPAT] = ALLOW;
for (int i = 0; i < FILE_OWNERID_MAX; i++) {
ownerid_policy[PROCESS_OWNERID_EXTEND][i] = ALLOW;
}
}
static int check_same_ownerid(struct cs_info *pcs_info, struct cs_info *fcs_info)
{
if ((pcs_info->id_type == fcs_info->id_type) &&
(pcs_info->ownerid == fcs_info->ownerid)) {
return 0;
}
return -EPERM;
}
int xpm_check_ownerid_policy(struct cs_info *pcs_info, struct cs_info *fcs_info)
{
uint32_t type;
if (!pcs_info || !fcs_info) {
xpm_log_error("input pcs_info or fcs_info is NULL");
return -EINVAL;
}
if ((pcs_info->id_type >= PROCESS_OWNERID_MAX) ||
(fcs_info->id_type >= FILE_OWNERID_MAX)) {
xpm_log_info("process or file ownerid exceed maximum value");
return -EINVAL;
}
type = ownerid_policy[pcs_info->id_type][fcs_info->id_type];
switch (type) {
case DENY:
return -EPERM;
case ALLOW:
return 0;
case CHECK:
return check_same_ownerid(pcs_info, fcs_info);
default:
xpm_log_error("input ownerid type is invalid: %u", type);
break;
}
return -EINVAL;
}
static int xpm_get_file_cs_info(struct cs_info *fcs_info,
struct exec_file_signature_info *info)
{
/* exec file is dm-verity */
if (exec_file_signature_is_dm_verity(info)) {
code_sign_set_ownerid(fcs_info, FILE_OWNERID_SYSTEM, NULL, 0);
return 0;
}
/* exec file is fs-verity */
if (exec_file_signature_is_fs_verity(info)) {
struct fsverity_info *vi = fsverity_get_info(info->inode);
if (!vi) {
xpm_log_error("get verity info failed in fs-verity");
return -EINVAL;
}
fcs_info->id_type = vi->fcs_info.id_type;
fcs_info->ownerid = vi->fcs_info.ownerid;
return 0;
}
xpm_log_error("invalid code signature info type");
return -EINVAL;
}
int xpm_get_process_cs_info(struct cs_info *pcs_info)
{
int ret;
struct exec_file_signature_info *info = NULL;
struct file *exe_file = NULL;
struct cs_info fcs_info = {0};
struct mm_struct *mm = current->mm;
if (!mm)
return -EINVAL;
/* process cs_info has not been init, just init from exe file */
if (mm->pcs_info.id_type == PROCESS_OWNERID_UNINIT) {
exe_file = get_task_exe_file(current);
if (!exe_file) {
xpm_log_error("xpm get exe_file failed");
return -ENOEXEC;
}
ret = get_exec_file_signature_info(exe_file, true, &info);
/* reduce exe_file reference count */
fput(exe_file);
if (ret || (info == NULL)) {
xpm_log_error("xpm get exe_file signature info failed");
return ret;
}
ret = xpm_get_file_cs_info(&fcs_info, info);
if (ret) {
xpm_log_error("xpm get exe_file cs info failed");
return ret;
}
/* process's ownerid is correspond to file */
mm->pcs_info.id_type = fcs_info.id_type;
mm->pcs_info.ownerid = fcs_info.ownerid;
}
pcs_info->id_type = mm->pcs_info.id_type;
pcs_info->ownerid = mm->pcs_info.ownerid;
return 0;
}
static int xpm_check_ownerid(struct vm_area_struct *vma,
struct exec_file_signature_info *info)
{
int ret;
struct cs_info pcs_info = {0};
struct cs_info fcs_info = {0};
ret = xpm_get_process_cs_info(&pcs_info);
if (ret) {
xpm_log_error("xpm get process cs_info falied");
return ret;
}
ret = xpm_get_file_cs_info(&fcs_info, info);
if (ret) {
xpm_log_error("xpm get file cs_info falied");
return ret;
}
return xpm_check_ownerid_policy(&pcs_info, &fcs_info);
}
static int xpm_avc_has_perm(u16 tclass, u32 requested)
{
struct av_decision avd;
u32 sid = current_sid();
return avc_has_perm_noaudit(&selinux_state, sid, sid, tclass, requested,
AVC_STRICT, &avd);
}
static int xpm_validate_signature(struct vm_area_struct *vma,
struct exec_file_signature_info *info)
{
unsigned long verified_data_end, vm_addr_end;
const struct inode *inode = (const struct inode *)info->inode;
if (IS_ERR_OR_NULL(info)) {
xpm_log_error("signature info is NULL");
return -EPERM;
}
if(!exec_file_signature_is_fs_verity(info))
return 0;
vm_addr_end = (vma->vm_pgoff << PAGE_SHIFT)
+ (vma->vm_end - vma->vm_start);
verified_data_end = PAGE_ALIGN(fsverity_get_verified_data_size(inode));
if (verified_data_end < vm_addr_end) {
xpm_log_error("data is out of verified data size");
return -EPERM;
}
return 0;
}
static int xpm_check_code_segment(bool is_exec, struct vm_area_struct *vma,
struct exec_file_signature_info *info)
{
int i;
unsigned long vm_addr_start, vm_addr_end;
unsigned long seg_addr_start, seg_addr_end;
struct exec_segment_info *segments = info->code_segments;
if (!is_exec)
return 0;
if (!segments) {
xpm_log_error("code segments is NULL");
return -EINVAL;
}
vm_addr_start = vma->vm_pgoff << PAGE_SHIFT;
vm_addr_end = vm_addr_start + (vma->vm_end - vma->vm_start);
for (i = 0; i < info->code_segment_count; i++) {
seg_addr_start = ALIGN_DOWN(segments[i].file_offset, PAGE_SIZE);
seg_addr_end = PAGE_ALIGN(segments[i].file_offset +
segments[i].size);
if ((vm_addr_start >= seg_addr_start) &&
(vm_addr_end <= seg_addr_end))
return 0;
}
return -EPERM;
}
static int xpm_check_signature(struct vm_area_struct *vma, unsigned long prot)
{
int ret;
bool is_exec;
struct exec_file_signature_info *info = NULL;
/* vma is non-executable or mmap in xpm region just return */
is_exec = !xpm_is_anonymous_vma(vma) && (prot & PROT_EXEC);
if (!((vma->vm_flags & VM_XPM) || is_exec))
return 0;
/* process has exec_no_sign permission just return */
if (xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_NO_SIGN) == 0)
return 0;
/* 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) {
report_mmap_event(GET_SIGN_FAIL, is_exec ? TYPE_ELF : TYPE_ABC,
vma, prot);
return ret;
}
do {
ret = xpm_validate_signature(vma, info);
if (ret) {
report_mmap_event(SIGN_INVALID,
is_exec ? TYPE_ELF : TYPE_ABC, vma, prot);
break;
}
ret = xpm_check_code_segment(is_exec, vma, info);
if (ret) {
report_mmap_event(DATA_MMAP_CODE,
is_exec ? TYPE_ELF : TYPE_ABC, vma, prot);
break;
}
ret = xpm_check_ownerid(vma, info);
if (ret) {
report_mmap_event(OWNERID_INCONSISTENT,
is_exec ? TYPE_ELF : TYPE_ABC, vma, prot);
break;
}
} while (0);
if (info)
put_exec_file_signature_info(info);
return ret;
}
static int xpm_check_prot(struct vm_area_struct *vma, unsigned long prot)
{
int ret;
bool is_anon;
is_anon = xpm_is_anonymous_vma(vma);
/* check for xpm region vma prot */
if (vma->vm_flags & VM_XPM) {
if (is_anon || (prot & PROT_EXEC)) {
xpm_log_error("xpm region mmap not allow anonymous or exec permission");
return -EPERM;
}
return 0;
}
/* check for anonymous vma prot, anonymous executable permission need
* controled by selinux
*/
if (is_anon && (prot & PROT_EXEC)) {
ret = xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_ANON_MEM);
if (ret) {
report_mmap_event(ANON_EXEC, TYPE_ANON, vma, prot);
return -EPERM;
}
return 0;
}
/* check for non-anonymous vma prot */
if (!is_anon && (prot & PROT_WRITE) && (prot & PROT_EXEC)) {
xpm_log_error("file mmap not allow write & exec permission");
return -EPERM;
}
return 0;
}
static int xpm_common_check(struct vm_area_struct *vma, unsigned long prot)
{
int ret;
do {
ret = xpm_check_prot(vma, prot);
if (ret)
break;
ret = xpm_check_signature(vma, prot);
} while (0);
return xpm_ret(ret);
}
static int xpm_mmap_check(struct vm_area_struct *vma)
{
return xpm_common_check(vma, vma->vm_flags);
}
static int xpm_mprotect_check(struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
{
(void)reqprot;
return xpm_common_check(vma, prot);
}
static struct security_hook_list xpm_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(mmap_region, xpm_mmap_check),
LSM_HOOK_INIT(file_mprotect, xpm_mprotect_check),
};
void xpm_register_security_hooks(void)
{
init_ownerid_policy();
security_add_hooks(xpm_hooks, ARRAY_SIZE(xpm_hooks), "xpm");
}
+11
View File
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_SECURITY_HOOKS_H
#define _XPM_SECURITY_HOOKS_H
void xpm_register_security_hooks(void);
#endif /* _XPM_SECURITY_HOOKS_H */
@@ -4,6 +4,7 @@
*/
#include <linux/proc_fs.h>
#include "dsmm_developer.h"
#include "xpm_log.h"
@@ -12,20 +13,21 @@
#define DSMM_DEVELOPER_PARAM_NAME "const.security.developermode.state"
static struct proc_dir_entry *g_dsmm_dir;
static uint32_t developer_state = STATE_UNINT;
static const char *g_developer_status[BUILD_VARIANT_MAX][DEVELOPER_PROC_STATUS_MAX] = {
{ DEVELOPER_STATUS_OFF, DEVELOPER_STATUS_ON, DEVELOPER_STATUS_OFF },
{ DEVELOPER_STATUS_ON, DEVELOPER_STATUS_ON, DEVELOPER_STATUS_OFF },
static uint32_t g_state_table[BUILD_VARIANT_MAX][CMDLINE_DEV_STATE_MAX] = {
{ STATE_OFF, STATE_ON, STATE_OFF },
{ STATE_ON, STATE_ON, STATE_ON },
};
static int get_developer_status(uint32_t *status)
{
if (!strstr(saved_command_line, "developer_mode=")) {
*status = DEVELOPER_PROC_STATUS_NA;
*status = CMDLINE_DEV_STATE_NA;
} else if (strstr(saved_command_line, "developer_mode=1")) {
*status = DEVELOPER_PROC_STATUS_ON;
*status = CMDLINE_DEV_STATE_ON;
} else if (strstr(saved_command_line, "developer_mode=0")) {
*status = DEVELOPER_PROC_STATUS_OFF;
*status = CMDLINE_DEV_STATE_OFF;
} else {
xpm_log_error("invalid developer_mode value in cmdline");
return -EINVAL;
@@ -48,20 +50,25 @@ static int get_build_variant(uint32_t *variant)
return 0;
}
const char *developer_mode_state(void)
int get_developer_mode_state(void)
{
uint32_t variant, status;
if (developer_state != STATE_UNINT)
return developer_state;
#ifdef CONFIG_DSMM_DEVELOPER_ENABLE
if (get_build_variant(&variant) || get_developer_status(&status)) {
xpm_log_error("get build variant or developer status failed");
return NULL;
developer_state = STATE_OFF;
} else {
developer_state = g_state_table[variant][status];
}
return g_developer_status[variant][status];
#else
return DEVELOPER_STATUS_ON;
developer_state = STATE_ON;
#endif
return developer_state;
}
#define PROC_DEVELOPER_LEN 50
@@ -69,16 +76,13 @@ static ssize_t dsmm_read_developer_proc(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
size_t len;
uint32_t state;
char proc_developer[PROC_DEVELOPER_LEN] = {0};
const char *developer_state = developer_mode_state();
if (!developer_state) {
xpm_log_error("developer mode state invalid");
return 0;
}
state = get_developer_mode_state();
len = snprintf(proc_developer, PROC_DEVELOPER_LEN - 1,
DSMM_DEVELOPER_PARAM_NAME"=%s", developer_state);
DSMM_DEVELOPER_PARAM_NAME"=%s",
state == STATE_ON ? "true" : "false");
return simple_read_from_buffer(buf, count, pos, proc_developer, len);
}
+40
View File
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _DSMM_DEVELOPER_H
#define _DSMM_DEVELOPER_H
#define STATE_UNINT 0
#define STATE_ON 1
#define STATE_OFF 2
enum build_variant {
BUILD_VARIANT_USER = 0,
BUILD_VARIANT_ENG,
BUILD_VARIANT_MAX,
};
enum cmdline_dev_state {
CMDLINE_DEV_STATE_NA = 0,
CMDLINE_DEV_STATE_ON,
CMDLINE_DEV_STATE_OFF,
CMDLINE_DEV_STATE_MAX,
};
void dsmm_developer_proc_create(void);
void dsmm_developer_proc_clean(void);
/**
* get_developer_mode_state - Get developer state of the device.
*
* @state: State of the device.
*
* Returns the developer state, STATE_ON or STATE_OFF.
*/
int get_developer_mode_state(void);
#endif /* _DSMM_DEVELOPER_H */
-31
View File
@@ -1,31 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef DSMM_DEVELOPER_H
#define DSMM_DEVELOPER_H
#define DEVELOPER_STATUS_ON "true"
#define DEVELOPER_STATUS_OFF "false"
enum build_variant {
BUILD_VARIANT_USER = 0,
BUILD_VARIANT_ENG,
BUILD_VARIANT_MAX,
};
enum developer_proc_status {
DEVELOPER_PROC_STATUS_NA = 0,
DEVELOPER_PROC_STATUS_ON,
DEVELOPER_PROC_STATUS_OFF,
DEVELOPER_PROC_STATUS_MAX,
};
const char *developer_mode_state(void);
void dsmm_developer_proc_create(void);
void dsmm_developer_proc_clean(void);
#endif // DSMM_DEVELOPER_H
-19
View File
@@ -1,19 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_MISC_H
#define _XPM_MISC_H
#include <linux/types.h>
struct xpm_region_info {
uint64_t addr_base;
uint64_t length;
};
int xpm_register_misc_device(void);
void xpm_deregister_misc_device(void);
#endif /* _XPM_MISC_H */
-86
View File
@@ -1,86 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _XPM_REPORT_H
#define _XPM_REPORT_H
#include <linux/sched.h>
#include <linux/mm.h>
enum xpm_event_id {
EVENT_INIT = 1011009110,
EVENT_FILE = 1011009111,
EVENT_MMAP = 1011009112,
EVENT_INTEGRITY = 1011009113,
};
enum xpm_event_type {
TYPE_DEVICEFS_UNINIT = 0,
TYPE_DEBUGFS_UNINIT,
TYPE_DM_DISABLE,
TYPE_FORMAT_UNDEF,
TYPE_ANON_EXEC,
TYPE_SIGN_INVALID,
TYPE_DATA_MMAP_CODE,
TYPE_INTEGRITY_RO,
TYPE_INTEGRITY_WT,
};
enum {
TYPE_ABC,
TYPE_ELF,
TYPE_ANON,
};
struct xpm_event_param {
char *event_type;
char *filename;
ktime_t timestamp;
pid_t pid;
struct vm_area_struct *vma;
struct page *page;
struct file *file;
int code;
unsigned long prot;
};
struct xpm_event_info {
char *event_type;
enum xpm_event_id event_id;
int (*set_content)(struct xpm_event_param *param, uint8_t *content,
uint32_t content_len);
};
#define MAX_CONTENT_LEN 900
#define XPM_EVENT_VERSION 0
#ifndef CONFIG_SECURITY_XPM_DEBUG
#define xpm_report_ratelimited(func, fmt, ...) \
do { \
static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, \
DEFAULT_RATELIMIT_BURST); \
if (__ratelimit(&_rs)) \
func(fmt, ##__VA_ARGS__); \
} while (0)
#else
#define xpm_report_ratelimited(func, fmt, ...) \
func(fmt, ##__VA_ARGS__);
#endif
#define JSTR(val) "\""#val"\""
#define JVAL_PAIR(val, format) JSTR(val) ": " #format
#define JSTR_PAIR(val, format) JSTR(val) ": " JSTR(format)
void report_init_event(enum xpm_event_type type);
void report_file_event(enum xpm_event_type type, struct file *file);
void report_mmap_event(enum xpm_event_type type, struct vm_area_struct *vma,
int code, int prot);
void report_integrity_event(enum xpm_event_type type,
struct vm_area_struct *vma, struct page *page);
#endif /* _XPM_REPORT_H */
+8 -6
View File
@@ -218,7 +218,7 @@ static bool dm_verity_is_enable(void)
dm_verity_enable_check = true;
if (!dm_verity_enable) {
dm_partition_table[0].s_dev = get_root_partition_dev(&root_path);
report_init_event(TYPE_DM_DISABLE);
report_init_event(DM_DISABLE);
}
return dm_verity_enable;
}
@@ -246,7 +246,7 @@ static bool is_dm_verity(struct file *file)
if (!dm_verity_enable_check) {
dm_partition_table[0].s_dev = get_root_partition_dev(&root_path);
dm_verity_enable_check = true;
report_init_event(TYPE_DM_DISABLE);
report_init_event(DM_DISABLE);
}
return dm_verity_check_for_path(file);
}
@@ -267,7 +267,7 @@ static bool is_fs_verity(struct file *file)
}
#endif
static int check_exec_file_is_verity(struct file *file)
static int check_exec_file_is_verity(struct file *file, bool is_exec)
{
#ifdef CONFIG_FS_VERITY
if (is_fs_verity(file))
@@ -278,7 +278,7 @@ static int check_exec_file_is_verity(struct file *file)
return FILE_SIGNATURE_DM_VERITY;
#ifdef CONFIG_SECURITY_CODE_SIGN
if (!elf_file_enable_fs_verity(file))
if (is_exec && !elf_file_enable_fs_verity(file))
return FILE_SIGNATURE_FS_VERITY;
#endif
@@ -531,8 +531,10 @@ need_parse:
return -ENOMEM;
} else {
ret = parse_elf_code_segment_info(file, &new_info);
if (ret < 0)
if (ret < 0) {
report_file_event(FORMAT_UNDEF, file);
return ret;
}
#ifdef CONFIG_SECURITY_XPM_DEBUG
test_print_info(file, type, new_info);
#endif
@@ -555,7 +557,7 @@ int get_exec_file_signature_info(struct file *file, bool is_exec,
if (file == NULL || info_ptr == NULL)
return -EINVAL;
type = check_exec_file_is_verity(file);
type = check_exec_file_is_verity(file, is_exec);
return get_elf_code_segment_info(file, is_exec, type, info_ptr);
}