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
13static 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 */
20static 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
65void 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
70void 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
82void 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
93void code_sign_init_salt(void)
94{
95	cs_salt = ktime_get_real_seconds();
96}
97
98void 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}