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, ¶m);
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, ¶m);
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, ¶m);
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, ¶m);
272 }
273