• 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/dcache.h>
7 #include <linux/fs.h>
8 #include <linux/fsverity.h>
9 #include <linux/mm.h>
10 #include <linux/mman.h>
11 #include <linux/rmap.h>
12 #include <linux/xpm.h>
13 
14 #ifdef CONFIG_HW_KERNEL_SG
15 #include <security/security_guard_collect.h>
16 #endif
17 
18 #include "code_sign_ext.h"
19 #include "fsverity_private.h"
20 #include "xpm_log.h"
21 #include "xpm_report.h"
22 
23 #define PROT_MASK (PROT_EXEC | PROT_READ | PROT_WRITE)
24 static char *code_type_tbl[] = {
25 	[TYPE_ABC] = "ABC",
26 	[TYPE_ELF] = "ELF",
27 	[TYPE_ANON] = "ANON"
28 };
29 
30 #ifndef CONFIG_HW_KERNEL_SG
31 typedef struct {
32 	unsigned long event_id;
33 	unsigned int version;
34 	unsigned int content_len;
35 	char content[0];
36 } event_info;
37 #endif
38 
xpm_report_security_info(const event_info * event)39 unsigned int xpm_report_security_info(const event_info *event)
40 {
41 	xpm_log_error("%d: %s", event->event_id, event->content);
42 
43 #ifdef CONFIG_HW_KERNEL_SG
44 	return report_security_info(event);
45 #else
46 	return 0;
47 #endif
48 }
49 
xpm_set_filename(struct file * file,struct xpm_report_info * info)50 static void xpm_set_filename(struct file *file, struct xpm_report_info *info)
51 {
52 	char *filename = NULL;
53 	char *buffer = NULL;
54 
55 	if (!file)
56 		return;
57 
58 	buffer = kzalloc(sizeof(info->filename), GFP_ATOMIC);
59 	if (!buffer) {
60 		xpm_log_error("alloc filename buffer failed");
61 		return;
62 	}
63 
64 	filename = file_path(file, buffer, sizeof(info->filename) - 1);
65 	if (IS_ERR(filename)) {
66 		xpm_log_error("xpm set file path failed");
67 	} else {
68 		strcpy(info->filename, filename);
69 	}
70 
71 	kfree(buffer);
72 }
73 
set_init_content(struct xpm_report_info * info,uint8_t * content,uint32_t content_len)74 static int set_init_content(struct xpm_report_info *info,
75 	uint8_t *content, uint32_t content_len)
76 {
77 	int len;
78 
79 	len = snprintf(content, content_len,
80 		"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)" }",
81 		info->event_type, info->timestamp);
82 
83 	if (len < 0 || len > content_len) {
84 		xpm_log_error("snprintf init content failed");
85 		return -EINVAL;
86 	}
87 
88 	return 0;
89 }
90 
set_mmap_content(struct xpm_report_info * info,uint8_t * content,uint32_t content_len)91 static int set_mmap_content(struct xpm_report_info *info, uint8_t *content,
92 	uint32_t content_len)
93 {
94 	int len;
95 
96 	len = snprintf(content, content_len,
97 		"{ "JSTR_PAIR(event_type, %s)", "JSTR_PAIR(code_type, %s)", "
98 		JVAL_PAIR(pid, %u)", "JSTR_PAIR(comm, %s)", "
99 		JSTR_PAIR(filename, %s)", "JVAL_PAIR(vm_prot, %lu)","
100 		JVAL_PAIR(vm_pgoff, %lu)", "JVAL_PAIR(vm_size, %lu)", "
101 		JVAL_PAIR(p_id_type, %u)", "JSTR_PAIR(p_ownerid, %u)", "
102 		JVAL_PAIR(f_id_type, %u)", "JSTR_PAIR(f_ownerid, %u)", "
103 		JSTR_PAIR(timestamp, %llu)" }",
104 		info->event_type, info->code_type, info->pid, info->comm,
105 		info->filename, info->vm_prot, info->vm_pgoff, info->vm_size,
106 		info->pcs_info.id_type, info->pcs_info.ownerid,
107 		info->fcs_info.id_type, info->fcs_info.ownerid,
108 		info->timestamp);
109 
110 	if (len < 0 || len > content_len) {
111 		xpm_log_error("snprintf code mmap content failed");
112 		return -EINVAL;
113 	}
114 
115 	return 0;
116 }
117 
set_file_content(struct xpm_report_info * info,uint8_t * content,uint32_t content_len)118 static int set_file_content(struct xpm_report_info *info,
119 	uint8_t *content, uint32_t content_len)
120 {
121 	int len;
122 
123 	len = snprintf(content, content_len,
124 		"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(pid, %u)", "
125 		JSTR_PAIR(comm, %s)", "JSTR_PAIR(filename, %s)", "
126 		JVAL_PAIR(timestap, %llu)" }",
127 		info->event_type, info->pid, info->comm,
128 		info->filename, info->timestamp);
129 
130 	if (len < 0 || len > content_len) {
131 		xpm_log_error("snprintf file format content failed");
132 		return -EINVAL;
133 	}
134 
135 	return 0;
136 }
137 
set_integrity_content(struct xpm_report_info * info,uint8_t * content,uint32_t content_len)138 static int set_integrity_content(struct xpm_report_info *info,
139 	uint8_t *content, uint32_t content_len)
140 {
141 	int len;
142 
143 	len = snprintf(content, content_len,
144 		"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(pid, %u)", "
145 		JSTR_PAIR(comm, %s)", "JSTR_PAIR(filename, %s)", "
146 		JSTR_PAIR(page_type, %s)", "JVAL_PAIR(page_index, %lu)", "
147 		JVAL_PAIR(vm_pgprot, %lu)", "JVAL_PAIR(timestamp, %llu)" }",
148 		info->event_type, info->pid, info->comm, info->filename,
149 		info->page_type, info->page_index, info->vm_pgprot,
150 		info->timestamp);
151 
152 	if (len < 0 || len > content_len) {
153 		xpm_log_error("snprintf init integrity failed");
154 		return -EINVAL;
155 	}
156 
157 	return 0;
158 }
159 
xpm_set_report_info(struct xpm_report_param * param,struct xpm_report_info * info)160 static void xpm_set_report_info(struct xpm_report_param *param,
161 	struct xpm_report_info *info)
162 {
163 	struct fsverity_info *vi = NULL;
164 	struct file *file = param->file;
165 	struct mm_struct *mm = current->mm;
166 
167 	info->event_type = param->event_type;
168 	info->code_type = code_type_tbl[param->code_type];
169 
170 	info->pid = current->pid;
171 	memcpy(info->comm, current->comm, TASK_COMM_LEN);
172 
173 	if (mm) {
174 		info->pcs_info.id_type = mm->pcs_info.id_type;
175 		info->pcs_info.ownerid = mm->pcs_info.ownerid;
176 	}
177 
178 	info->vm_prot = param->vm_prot & PROT_MASK;
179 	if (param->vma) {
180 		info->vm_pgoff = param->vma->vm_pgoff;
181 		info->vm_size = param->vma->vm_end - param->vma->vm_start;
182 		info->vm_pgprot = param->vma->vm_page_prot.pgprot & PROT_MASK;
183 		file = param->vma->vm_file;
184 	}
185 
186 	if (param->page) {
187 		info->page_type = PageKsm(param->page) ?
188 			"[ksm]" : PageAnon(param->page) ? "[anon]" : "[file]";
189 		info->page_index = param->page->index;
190 	}
191 
192 	/* init file ownerid type SYSTEM */
193 	info->fcs_info.id_type = FILE_OWNERID_SYSTEM;
194 	if (file) {
195 		xpm_set_filename(file, info);
196 		vi = fsverity_get_info(file_inode(file));
197 		if (vi) {
198 			info->fcs_info.id_type = vi->fcs_info.id_type;
199 			info->fcs_info.ownerid = vi->fcs_info.ownerid;
200 		}
201 	}
202 
203 	info->timestamp = ktime_get_real_seconds();
204 }
205 
xpm_report_event(struct xpm_report_param * param)206 static int xpm_report_event(struct xpm_report_param *param)
207 {
208 	int ret;
209 	event_info *event = NULL;
210 	struct xpm_report_info *info = NULL;
211 
212 	if (!param->event_type) {
213 		xpm_log_error("xpm event type is NULL");
214 		return -EINVAL;
215 	}
216 
217 	info = kzalloc(sizeof(struct xpm_report_info), GFP_ATOMIC);
218 	if (!info) {
219 		xpm_log_error("alloc xpm report info struct failed");
220 		return -ENOMEM;
221 	}
222 
223 	event = kzalloc(sizeof(event_info) + MAX_CONTENT_LEN, GFP_ATOMIC);
224 	if (!event) {
225 		xpm_log_error("alloc security guard event failed");
226 		kfree(info);
227 		return -ENOMEM;
228 	}
229 
230 	do {
231 		event->version = XPM_EVENT_VERSION;
232 		event->event_id = param->event_id;
233 
234 		/* set xpm report info from param */
235 		xpm_set_report_info(param, info);
236 		ret = param->set_content(info, event->content, MAX_CONTENT_LEN);
237 		if (ret) {
238 			xpm_log_error("type [%s] set content failed",
239 				param->event_type);
240 			break;
241 		}
242 		event->content_len = strlen(event->content);
243 
244 		ret = xpm_report_security_info(event);
245 		if (ret) {
246 			xpm_log_error("type [%s] report security info failed",
247 				param->event_type);
248 			break;
249 		}
250 
251 	} while (0);
252 
253 	kfree(info);
254 	kfree(event);
255 	return ret;
256 }
257 
report_init_event(char * event_type)258 void report_init_event(char *event_type)
259 {
260 	struct xpm_report_param param = {0};
261 
262 	param.event_type = event_type;
263 	param.event_id = EVENT_INIT;
264 	param.set_content = &set_init_content;
265 
266 	xpm_report_ratelimited(xpm_report_event, &param);
267 }
268 
report_file_event(char * event_type,struct file * file)269 void report_file_event(char *event_type, struct file *file)
270 {
271 	struct xpm_report_param param = {0};
272 
273 	param.event_type = event_type;
274 	param.event_id = EVENT_FILE;
275 	param.file = file;
276 	param.set_content = &set_file_content;
277 
278 	xpm_report_ratelimited(xpm_report_event, &param);
279 }
280 
report_mmap_event(char * event_type,enum xpm_code_type code_type,struct vm_area_struct * vma,unsigned long vm_prot)281 void report_mmap_event(char *event_type, enum xpm_code_type code_type,
282 	struct vm_area_struct *vma, unsigned long vm_prot)
283 {
284 	struct xpm_report_param param = {0};
285 
286 	param.event_type = event_type;
287 	param.event_id = EVENT_MMAP;
288 	param.code_type = code_type;
289 	param.vma = vma;
290 	param.vm_prot = vm_prot;
291 	param.set_content = &set_mmap_content;
292 
293 	xpm_report_ratelimited(xpm_report_event, &param);
294 }
295 
report_integrity_event(char * event_type,struct vm_area_struct * vma,struct page * page)296 void report_integrity_event(char *event_type, struct vm_area_struct *vma,
297 	struct page *page)
298 {
299 	struct xpm_report_param param = {0};
300 
301 	param.event_type = event_type;
302 	param.event_id = EVENT_INTEGRITY;
303 	param.vma = vma;
304 	param.page = page;
305 	param.set_content = &set_integrity_content;
306 
307 	xpm_report_ratelimited(xpm_report_event, &param);
308 }
309