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, ¶m);
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, ¶m);
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, ¶m);
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, ¶m);
308 }
309