• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2023 Huawei Device Co., Ltd.
4  */
5 
6 #include <linux/code_sign.h>
7 #include <linux/fsverity.h>
8 #include <linux/stringhash.h>
9 
10 #include "code_sign_ext.h"
11 #include "code_sign_log.h"
12 
13 static time64_t cs_salt;
14 
15 /**
16  * Validate code sign descriptor
17  *
18  * Return: 1 on code sign version, 0 on basic version, and -errno on failure
19  */
check_code_sign_descriptor(const struct inode * inode,const struct code_sign_descriptor * desc)20 static inline int check_code_sign_descriptor(const struct inode *inode,
21 	const struct code_sign_descriptor *desc)
22 {
23 	u64 tree_offset = le64_to_cpu(desc->tree_offset);
24 
25 	if (!desc->cs_version)
26 		return 0;
27 
28 	// when calc pgtypeinfo_size, trans bit size to byte size
29 	u32 pgtypeinfo_size_bytes = le32_to_cpu(desc->pgtypeinfo_size) / 8;
30 	if (le64_to_cpu(desc->pgtypeinfo_off) > le64_to_cpu(desc->data_size) - pgtypeinfo_size_bytes) {
31 		code_sign_log_error("Wrong offset: %llu (pgtypeinfo_off) > %llu (data_size) - %u (pgtypeinfo_size)",
32 				le64_to_cpu(desc->pgtypeinfo_off), le64_to_cpu(desc->data_size), pgtypeinfo_size_bytes);
33 		return -EINVAL;
34 	}
35 
36 	if (le64_to_cpu(desc->data_size) > inode->i_size) {
37 		code_sign_log_error("Wrong data_size: %llu (desc) > %lld (inode)",
38 				le64_to_cpu(desc->data_size), inode->i_size);
39 		return -EINVAL;
40 	}
41 
42 	if (desc->salt_size > sizeof(desc->salt)) {
43 		code_sign_log_error("Invalid salt_size: %u", desc->salt_size);
44 		return -EINVAL;
45 	}
46 
47 	if (IS_INSIDE_TREE(desc)) {
48 		if ((tree_offset > inode->i_size) || (tree_offset % PAGE_SIZE != 0)) {
49 			code_sign_log_error(
50 				"Wrong tree_offset: %llu (desc) > %lld (file size) or alignment is wrong",
51 					tree_offset, inode->i_size);
52 			return -EINVAL;
53 		}
54 	} else {
55 		if (tree_offset != 0) {
56 			code_sign_log_error(
57 					"Wrong tree_offset without tree: %llu (desc) != 0",
58 					tree_offset);
59 			return -EINVAL;
60 		}
61 	}
62 	return 1;
63 }
64 
code_sign_check_descriptor(const struct inode * inode,const void * desc,int * ret)65 void code_sign_check_descriptor(const struct inode *inode, const void *desc, int *ret)
66 {
67 	*ret = check_code_sign_descriptor(inode, CONST_CAST_CODE_SIGN_DESC(desc));
68 }
69 
code_sign_before_measurement(void * _desc,int * ret)70 void code_sign_before_measurement(void *_desc, int *ret)
71 {
72 	struct code_sign_descriptor *desc = CAST_CODE_SIGN_DESC(_desc);
73 
74 	if (desc->cs_version == 1) {
75 		*ret = desc->cs_version;
76 		desc->cs_version = 0;
77 	} else {
78 		*ret = desc->cs_version;
79 	}
80 }
81 
code_sign_after_measurement(void * _desc,int version)82 void code_sign_after_measurement(void *_desc, int version)
83 {
84 	struct code_sign_descriptor *desc = CAST_CODE_SIGN_DESC(_desc);
85 
86 	if (version == 1) {
87 		// restore cs_version
88 		desc->cs_version = desc->version;
89 		desc->version = version;
90 	}
91 }
92 
code_sign_init_salt(void)93 void code_sign_init_salt(void)
94 {
95 	cs_salt = ktime_get_real_seconds();
96 }
97 
code_sign_set_ownerid(struct cs_info * cs_info,uint32_t id_type,const char * id_str,uint32_t id_len)98 void code_sign_set_ownerid(struct cs_info *cs_info, uint32_t id_type,
99 	const char *id_str, uint32_t id_len)
100 {
101 	if (!cs_info) {
102 		code_sign_log_error("Input cs_info is NULL");
103 		return;
104 	}
105 
106 	cs_info->id_type = id_type;
107 	if (!id_str || id_len == 0)
108 		cs_info->ownerid = 0;
109 	else
110 		cs_info->ownerid = full_name_hash(cs_salt, id_str, id_len);
111 }