diff --git a/code_sign/code_sign_elf.c b/code_sign/code_sign_elf.c index ef5782667f5c3827147725ab432199e12c73c31d..9c9a3dccffd6692d261c26a639eecffe4c093492 100644 --- a/code_sign/code_sign_elf.c +++ b/code_sign/code_sign_elf.c @@ -10,6 +10,7 @@ #include "dsmm_developer.h" #include "code_sign_elf.h" #include "code_sign_log.h" +#include "verify_cert_chain.h" #define SIGN_HEAD_SIZE (sizeof(sign_head_t)) @@ -94,12 +95,28 @@ static int get_fsverity_desc(sign_block_t *sign_block, char *sign_data_ptr) return -EINVAL; } - sign_block->fsverity_desc = (fs_verity_desc_t *) (sign_data_ptr + sign_block->code_signing_block_hdr.offset + sign_block->fsverity_desc = (struct code_sign_descriptor *) (sign_data_ptr + sign_block->code_signing_block_hdr.offset + sizeof(tl_header_t) + sign_block->merkle_tree_hdr.length + sizeof(tl_header_t)); return 0; } +static int validate_elf_source(const struct code_sign_descriptor *desc) +{ + const u32 sig_size = le32_to_cpu(desc->sig_size); + int ret = 0; + + code_sign_verify_certchain(desc->signature, sig_size, NULL, &ret); + if (ret < 0) + return ret; + + if (ret <= DEBUG_CODE_START || ret >= DEBUG_CODE_END || ret == DEBUG_DEVELOPER_CODE) { + code_sign_log_error("invalid elf source, type: %d", ret); + return -EKEYREJECTED; + } + return 0; +} + static int enable_by_sign_head(struct file *fp, struct inode *inode, long long fsize, char *sign_head_ptr) { sign_block_t sign_block; @@ -154,6 +171,11 @@ static int enable_by_sign_head(struct file *fp, struct inode *inode, long long f if (err) /* -ETXTBSY */ goto out_drop_write; + /* validate cert chain of elf signer */ + err = validate_elf_source(sign_block.fsverity_desc); + if (err) + goto out; + /* fsverity_enable_with_descriptor in fs/verity/enable.c */ err = fsverity_enable_with_descriptor(fp, (void *)(sign_block.fsverity_desc), sign_block.fsverity_desc_hdr.length); if (err) { diff --git a/code_sign/code_sign_elf.h b/code_sign/code_sign_elf.h index 3348f9fa48bc3c8ad97a7292557c1128495f10ce..b091017984f83e46784fccfa8f6cb61e3512a5e1 100644 --- a/code_sign/code_sign_elf.h +++ b/code_sign/code_sign_elf.h @@ -7,6 +7,7 @@ #define _CODE_SIGN_ELF_H #include +#include #define PAGE_SIZE_4K 12 @@ -36,7 +37,7 @@ * | |hash alg (1 byte )| | * | |log2blocksize (1 byte )| | * | |salt size (1 byte )| | - * | |signature size (4 bytes)| fs verity | + * | |signature size (4 bytes)| code sign | * | |data size (8 bytes)| block | * | |root hash (64 bytes)| | * | |salt (32 bytes)| | @@ -85,7 +86,6 @@ typedef struct __u32 length; } tl_header_t; - typedef struct { __u32 type; @@ -93,24 +93,6 @@ typedef struct __u32 offset; } block_hdr_t; -typedef struct -{ - __u8 version; - __u8 hash_algorithm; - __u8 log2_block_size; - __u8 salt_size; - __u32 signature_size; - __u64 data_size; - __u8 root_hash[64]; - __u8 salt[32]; - __u32 flags; - __u32 reserved; - __u64 tree_offset; - __u8 reserved_buf[127]; - __u8 cs_version; - char signature[]; -} fs_verity_desc_t; - #pragma pack(pop) typedef struct @@ -129,7 +111,7 @@ typedef struct tl_header_t merkle_tree_hdr; merkle_tree_t *merkle_tree; tl_header_t fsverity_desc_hdr; - fs_verity_desc_t *fsverity_desc; + struct code_sign_descriptor *fsverity_desc; /* sign head */ sign_head_t sign_head; diff --git a/code_sign/code_sign_ioctl.c b/code_sign/code_sign_ioctl.c index 208438bc099540026a1919718b6505fd1213b27a..18767cb22856481a36a2060bbc8271dc84269788 100644 --- a/code_sign/code_sign_ioctl.c +++ b/code_sign/code_sign_ioctl.c @@ -74,22 +74,28 @@ int code_sign_check_caller(char *caller) rc = security_sid_to_context(&selinux_state, sid, &context, &context_len); if (rc) - return rc; + return -EINVAL; code_sign_log_debug("sid=%d, context=%s", sid, context); - if (strncmp(caller, context, strlen(caller))) + if (!strncmp(caller, context, strlen(caller))) return 0; - else - return -EKEYREJECTED; + + return -EPERM; } int cert_chain_insert(struct rb_root *root, struct cert_source *cert) { - // procs except key_enable are only allowed to insert developer_code - if (!code_sign_check_caller(KEY_ENABLE_CTX) && !(cert->path_type == RELEASE_DEVELOPER_CODE - || cert->path_type == DEBUG_DEVELOPER_CODE)) { - code_sign_log_error("no permission to insert code %d", cert->path_type); - return -EKEYREJECTED; + int ret = code_sign_check_caller(KEY_ENABLE_CTX); + if (ret == -EINVAL) { + code_sign_log_error("load SELinux context failed"); + return -EINVAL; + } else if (ret == -EPERM) { + // procs except key_enable are only allowed to insert developer_code + if (!(cert->path_type == RELEASE_DEVELOPER_CODE + || cert->path_type == DEBUG_DEVELOPER_CODE)) { + code_sign_log_error("no permission to insert code %d", cert->path_type); + return -EPERM; + } } spin_lock(&cert_chain_tree_lock); diff --git a/code_sign/verify_cert_chain.c b/code_sign/verify_cert_chain.c index 2409a7e952cfb1ec49d8fa734f83c5d4f60b5990..908dd6babb36cd9abf191993ad4dd1757a64498c 100644 --- a/code_sign/verify_cert_chain.c +++ b/code_sign/verify_cert_chain.c @@ -66,6 +66,9 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, static void set_file_ownerid(struct cs_info *cs_info, int path_type, struct pkcs7_signed_info *sinfo) { + if (cs_info == NULL) + return; + /* 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);