• 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/mm.h>
7 #include <linux/rmap.h>
8 #include <linux/mman.h>
9 #include <linux/fs.h>
10 #include <linux/xpm.h>
11 #include <linux/dcache.h>
12 #ifdef CONFIG_HW_KERNEL_SG
13 #include <security/security_guard_collect.h>
14 #endif
15 #include "xpm_log.h"
16 #include "xpm_report.h"
17 
18 #ifndef CONFIG_HW_KERNEL_SG
19 typedef struct {
20 	unsigned long event_id;
21 	unsigned int version;
22 	unsigned int content_len;
23 	char content[0];
24 } event_info;
25 
report_security_info(const event_info * event)26 unsigned int report_security_info(const event_info *event)
27 {
28 	xpm_log_info("%d: %s", event->event_id, event->content);
29 	return 0;
30 }
31 #endif
32 
xpm_get_filename(struct xpm_event_param * param,char * buf,int len)33 static char *xpm_get_filename(struct xpm_event_param *param, char *buf, int len)
34 {
35 	char *filename = NULL;
36 	struct file *file = NULL;
37 
38 	if (param->file)
39 		file = param->file;
40 	else if (param->vma && param->vma->vm_file)
41 		file = param->vma->vm_file;
42 	else
43 		return NULL;
44 
45 	filename = d_absolute_path(&file->f_path, buf, len);
46 	if (IS_ERR(filename)) {
47 		xpm_log_error("xpm get absolute path failed");
48 		return NULL;
49 	}
50 
51 	return filename;
52 }
53 
set_init_content(struct xpm_event_param * param,uint8_t * content,uint32_t content_len)54 static int set_init_content(struct xpm_event_param *param,
55 	uint8_t *content, uint32_t content_len)
56 {
57 	int len;
58 
59 	len = snprintf(content, content_len,
60 		"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)" }",
61 		param->event_type, param->timestamp);
62 
63 	if (len < 0 || len > content_len) {
64 		xpm_log_error("snprintf init content failed");
65 		return -EINVAL;
66 	}
67 
68 	return 0;
69 }
70 
71 #define PROT_MASK (PROT_EXEC | PROT_READ | PROT_WRITE)
72 const static char *code_type[] = {
73 	[TYPE_ABC] = "ABC",
74 	[TYPE_ELF] = "ELF",
75 	[TYPE_ANON] = "ANON"
76 };
set_mmap_content(struct xpm_event_param * param,uint8_t * content,uint32_t content_len)77 static int set_mmap_content(struct xpm_event_param *param, uint8_t *content,
78 	uint32_t content_len)
79 {
80 	int len;
81 
82 	if (!param->vma) {
83 		xpm_log_error("input vma is NULL");
84 		return -EINVAL;
85 	}
86 
87 	len = snprintf(content, content_len,
88 		"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)", "
89 		JVAL_PAIR(pid, %u)", "JSTR_PAIR(filename, %s)", "
90 		JSTR_PAIR(code_type, %s)", "JVAL_PAIR(prot, %lu)","
91 		JVAL_PAIR(pgoff, %lu)", "JVAL_PAIR(size, %lu)" }",
92 		param->event_type, param->timestamp, param->pid,
93 		param->filename ? param->filename : "",
94 		code_type[param->code], param->prot & PROT_MASK,
95 		param->vma->vm_pgoff,
96 		param->vma->vm_end - param->vma->vm_start);
97 
98 	if (len < 0 || len > content_len) {
99 		xpm_log_error("snprintf code mmap content failed");
100 		return -EINVAL;
101 	}
102 
103 	return 0;
104 }
105 
set_file_content(struct xpm_event_param * param,uint8_t * content,uint32_t content_len)106 static int set_file_content(struct xpm_event_param *param,
107 	uint8_t *content, uint32_t content_len)
108 {
109 	int len;
110 
111 	len = snprintf(content, content_len,
112 		"{ "JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)", "
113 		JVAL_PAIR(pid, %u)", "JSTR_PAIR(filename, %s)" }",
114 		param->event_type, param->timestamp, param->pid,
115 		param->filename ? param->filename : "");
116 
117 	if (len < 0 || len > content_len) {
118 		xpm_log_error("snprintf file format content failed");
119 		return -EINVAL;
120 	}
121 
122 	return 0;
123 }
124 
set_integrity_content(struct xpm_event_param * param,uint8_t * content,uint32_t content_len)125 static int set_integrity_content(struct xpm_event_param *param,
126 	uint8_t *content, uint32_t content_len)
127 {
128 	int len;
129 	char *page_type;
130 
131 	if (!param->vma || !param->page) {
132 		xpm_log_error("input vma or page is NULL");
133 		return -EINVAL;
134 	}
135 
136 	page_type = PageKsm(param->page) ?
137 		"[ksm]" : PageAnon(param->page) ? "[anon]" : "[file]";
138 
139 	len = snprintf(content, content_len,
140 		"{ " JSTR_PAIR(event_type, %s)", "JVAL_PAIR(timestamp, %llu)", "
141 		JVAL_PAIR(pid, %u)","JSTR_PAIR(page_type, %s)", "
142 		JSTR_PAIR(filename, %s)", "JVAL_PAIR(page_index, %lu)","
143 		JVAL_PAIR(page_prot, %lu)" }",
144 		param->event_type, param->timestamp, param->pid, page_type,
145 		param->filename ? param->filename : "", param->page->index,
146 		param->vma->vm_page_prot.pgprot & PROT_MASK);
147 
148 	if (len < 0 || len > content_len) {
149 		xpm_log_error("snprintf init integrity failed");
150 		return -EINVAL;
151 	}
152 
153 	return 0;
154 }
155 
156 static const struct xpm_event_info xpm_event[] = {
157 	[TYPE_DEVICEFS_UNINIT] = { "devicefs uninitialized",
158 		EVENT_INIT, set_init_content },
159 	[TYPE_DEBUGFS_UNINIT] = { "debugfs uninitialized",
160 		EVENT_INIT, set_init_content },
161 	[TYPE_DM_DISABLE] = { "dm-verity disable",
162 		EVENT_INIT, set_init_content },
163 	[TYPE_FORMAT_UNDEF] = { "unkown file format",
164 		EVENT_FILE, set_file_content },
165 	[TYPE_ANON_EXEC] = { "anon executed",
166 		EVENT_MMAP, set_file_content },
167 	[TYPE_SIGN_INVALID] = { "invalid signature",
168 		EVENT_MMAP, set_mmap_content },
169 	[TYPE_DATA_MMAP_CODE] = { "data mmap code",
170 		EVENT_MMAP, set_mmap_content },
171 	[TYPE_INTEGRITY_RO] = { "code tampered",
172 		EVENT_INTEGRITY, set_integrity_content },
173 	[TYPE_INTEGRITY_WT] = { "data executed",
174 		EVENT_INTEGRITY, set_integrity_content },
175 };
176 
report_event_inner(enum xpm_event_type type,struct xpm_event_param * param,event_info * event)177 static int report_event_inner(enum xpm_event_type type,
178 	struct xpm_event_param *param, event_info *event)
179 {
180 	int ret;
181 
182 	ret = xpm_event[type].set_content(param, event->content,
183 		MAX_CONTENT_LEN);
184 	if (ret) {
185 		xpm_log_error("type [%d] set content failed", type);
186 		return ret;
187 	}
188 	event->content_len = strlen(event->content);
189 	event->event_id = xpm_event[type].event_id;
190 	event->version = XPM_EVENT_VERSION;
191 
192 	ret = report_security_info(event);
193 	if (ret) {
194 		xpm_log_error("type [%d] report security info failed", type);
195 		return ret;
196 	}
197 
198 	return 0;
199 }
200 
xpm_report_event(enum xpm_event_type type,struct xpm_event_param * param)201 static int xpm_report_event(enum xpm_event_type type,
202 	struct xpm_event_param *param)
203 {
204 	int ret;
205 	event_info *sg_event;
206 	char *buf;
207 
208 	if (!(xpm_event[type].set_content)) {
209 		xpm_log_error("type [%d] set content func invalid", type);
210 		return -EINVAL;
211 	}
212 
213 	sg_event = kzalloc(sizeof(event_info) + MAX_CONTENT_LEN, GFP_KERNEL);
214 	if (!sg_event) {
215 		xpm_log_error("alloc security guard event failed");
216 		return -ENOMEM;
217 	}
218 
219 	buf = __getname();
220 	if (!buf) {
221 		xpm_log_error("alloc file name buf failed");
222 		kfree(sg_event);
223 		return -ENOMEM;
224 	}
225 
226 	param->event_type = xpm_event[type].event_type;
227 	param->filename = xpm_get_filename(param, buf, PATH_MAX);
228 	param->timestamp = ktime_get_real_seconds();
229 	param->pid = current->pid;
230 
231 	ret = report_event_inner(type, param, sg_event);
232 
233 	__putname(buf);
234 	kfree(sg_event);
235 	return ret;
236 }
237 
report_init_event(enum xpm_event_type type)238 void report_init_event(enum xpm_event_type type)
239 {
240 	struct xpm_event_param param = {0};
241 
242 	xpm_report_ratelimited(xpm_report_event, type, &param);
243 }
244 
report_file_event(enum xpm_event_type type,struct file * file)245 void report_file_event(enum xpm_event_type type, struct file *file)
246 {
247 	struct xpm_event_param param = {0};
248 
249 	param.file = file;
250 	xpm_report_ratelimited(xpm_report_event, type, &param);
251 }
252 
report_mmap_event(enum xpm_event_type type,struct vm_area_struct * vma,int code,int prot)253 void report_mmap_event(enum xpm_event_type type, struct vm_area_struct *vma,
254 	int code, int prot)
255 {
256 	struct xpm_event_param param = {0};
257 
258 	param.vma = vma;
259 	param.code = code;
260 	param.prot = prot;
261 	xpm_report_ratelimited(xpm_report_event, type, &param);
262 }
263 
report_integrity_event(enum xpm_event_type type,struct vm_area_struct * vma,struct page * page)264 void report_integrity_event(enum xpm_event_type type,
265 	struct vm_area_struct *vma, struct page *page)
266 {
267 	struct xpm_event_param param = {0};
268 
269 	param.vma = vma;
270 	param.page = page;
271 	xpm_report_ratelimited(xpm_report_event, type, &param);
272 }
273