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 if (desc->__reserved1 ||
29 memchr_inv(desc->__reserved2, 0, sizeof(desc->__reserved2)))
30 return -EINVAL;
31
32 if (le64_to_cpu(desc->data_size) > inode->i_size) {
33 code_sign_log_error("Wrong data_size: %llu (desc) > %lld (inode)",
34 le64_to_cpu(desc->data_size), inode->i_size);
35 return -EINVAL;
36 }
37
38 if (desc->salt_size > sizeof(desc->salt)) {
39 code_sign_log_error("Invalid salt_size: %u", desc->salt_size);
40 return -EINVAL;
41 }
42
43 if (IS_INSIDE_TREE(desc)) {
44 if ((tree_offset > inode->i_size) || (tree_offset % PAGE_SIZE != 0)) {
45 code_sign_log_error(
46 "Wrong tree_offset: %llu (desc) > %lld (file size) or alignment is wrong",
47 tree_offset, inode->i_size);
48 return -EINVAL;
49 }
50 } else {
51 if (tree_offset != 0) {
52 code_sign_log_error(
53 "Wrong tree_offset without tree: %llu (desc) != 0",
54 tree_offset);
55 return -EINVAL;
56 }
57 }
58 return 1;
59 }
60
code_sign_check_descriptor(const struct inode * inode,const void * desc,int * ret)61 void code_sign_check_descriptor(const struct inode *inode, const void *desc, int *ret)
62 {
63 *ret = check_code_sign_descriptor(inode, CONST_CAST_CODE_SIGN_DESC(desc));
64 }
65
code_sign_before_measurement(void * _desc,int * ret)66 void code_sign_before_measurement(void *_desc, int *ret)
67 {
68 struct code_sign_descriptor *desc = CAST_CODE_SIGN_DESC(_desc);
69
70 if (desc->cs_version) {
71 // replace version with cs_version
72 desc->version = desc->cs_version;
73 desc->cs_version = 0;
74 *ret = desc->version;
75 }
76 }
77
code_sign_after_measurement(void * _desc,int version)78 void code_sign_after_measurement(void *_desc, int version)
79 {
80 struct code_sign_descriptor *desc = CAST_CODE_SIGN_DESC(_desc);
81
82 if (version) {
83 // restore cs_version
84 desc->cs_version = desc->version;
85 desc->version = version;
86 }
87 }
88
code_sign_init_salt(void)89 void code_sign_init_salt(void)
90 {
91 cs_salt = ktime_get_real_seconds();
92 }
93
code_sign_set_ownerid(struct cs_info * cs_info,uint32_t id_type,const char * id_str,uint32_t id_len)94 void code_sign_set_ownerid(struct cs_info *cs_info, uint32_t id_type,
95 const char *id_str, uint32_t id_len)
96 {
97 if (!cs_info) {
98 code_sign_log_error("Input cs_info is NULL");
99 return;
100 }
101
102 cs_info->id_type = id_type;
103 if (!id_str || id_len == 0)
104 cs_info->ownerid = 0;
105 else
106 cs_info->ownerid = full_name_hash(cs_salt, id_str, id_len);
107 }