1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 */
5
6 #include <linux/mman.h>
7 #include <linux/mm_types.h>
8 #include <linux/version.h>
9
10 #include "avc.h"
11 #include "objsec.h"
12 #include "exec_signature_info.h"
13 #include "fsverity_private.h"
14 #include "code_sign_ext.h"
15 #include "dsmm_secureshield.h"
16 #include "xpm_common.h"
17 #include "xpm_debugfs.h"
18 #include "xpm_log.h"
19 #include "xpm_report.h"
20 #include "xpm_security_hooks.h"
21
22 enum ownerid_policy_type {
23 DENY = 0,
24 ALLOW,
25 CHECK,
26 };
27
28 static uint32_t ownerid_policy[PROCESS_OWNERID_MAX][FILE_OWNERID_MAX] __ro_after_init;
29
init_ownerid_policy(void)30 static void init_ownerid_policy(void)
31 {
32 ownerid_policy[PROCESS_OWNERID_SYSTEM][FILE_OWNERID_SYSTEM] = ALLOW;
33
34 ownerid_policy[PROCESS_OWNERID_APP][FILE_OWNERID_SYSTEM] = ALLOW;
35 ownerid_policy[PROCESS_OWNERID_APP][FILE_OWNERID_SHARED] = ALLOW;
36 ownerid_policy[PROCESS_OWNERID_APP][FILE_OWNERID_APP] = CHECK;
37
38 ownerid_policy[PROCESS_OWNERID_DEBUG][FILE_OWNERID_SYSTEM] = ALLOW;
39 ownerid_policy[PROCESS_OWNERID_DEBUG][FILE_OWNERID_SHARED] = ALLOW;
40 ownerid_policy[PROCESS_OWNERID_DEBUG][FILE_OWNERID_DEBUG] = ALLOW;
41
42 ownerid_policy[PROCESS_OWNERID_COMPAT][FILE_OWNERID_SYSTEM] = ALLOW;
43 ownerid_policy[PROCESS_OWNERID_COMPAT][FILE_OWNERID_COMPAT] = ALLOW;
44
45 for (int i = 0; i < FILE_OWNERID_MAX; i++) {
46 ownerid_policy[PROCESS_OWNERID_EXTEND][i] = ALLOW;
47 }
48 }
49
check_same_ownerid(struct cs_info * pcs_info,struct cs_info * fcs_info)50 static int check_same_ownerid(struct cs_info *pcs_info, struct cs_info *fcs_info)
51 {
52 if ((pcs_info->id_type == fcs_info->id_type) &&
53 (pcs_info->ownerid == fcs_info->ownerid)) {
54 return 0;
55 }
56
57 return -EPERM;
58 }
59
xpm_check_ownerid_policy(struct cs_info * pcs_info,struct cs_info * fcs_info)60 int xpm_check_ownerid_policy(struct cs_info *pcs_info, struct cs_info *fcs_info)
61 {
62 uint32_t type;
63
64 if (!pcs_info || !fcs_info) {
65 xpm_log_error("input pcs_info or fcs_info is NULL");
66 return -EINVAL;
67 }
68
69 if ((pcs_info->id_type >= PROCESS_OWNERID_MAX) ||
70 (fcs_info->id_type >= FILE_OWNERID_MAX)) {
71 xpm_log_info("process or file ownerid exceed maximum value");
72 return -EINVAL;
73 }
74
75 type = ownerid_policy[pcs_info->id_type][fcs_info->id_type];
76 switch (type) {
77 case DENY:
78 return -EPERM;
79 case ALLOW:
80 return 0;
81 case CHECK:
82 return check_same_ownerid(pcs_info, fcs_info);
83 default:
84 xpm_log_error("input ownerid type is invalid: %u", type);
85 break;
86 }
87
88 return -EINVAL;
89 }
90
xpm_get_file_cs_info(struct cs_info * fcs_info,struct exec_file_signature_info * info)91 static int xpm_get_file_cs_info(struct cs_info *fcs_info,
92 struct exec_file_signature_info *info)
93 {
94 /* exec file is dm-verity */
95 if (exec_file_signature_is_dm_verity(info)) {
96 code_sign_set_ownerid(fcs_info, FILE_OWNERID_SYSTEM, NULL, 0);
97 return 0;
98 }
99
100 /* exec file is fs-verity */
101 if (exec_file_signature_is_fs_verity(info)) {
102 struct fsverity_info *vi = fsverity_get_info(info->inode);
103 if (!vi) {
104 xpm_log_error("get verity info failed in fs-verity");
105 return -EINVAL;
106 }
107
108 fcs_info->id_type = vi->fcs_info.id_type;
109 fcs_info->ownerid = vi->fcs_info.ownerid;
110 return 0;
111 }
112
113 xpm_log_error("invalid code signature info type");
114 return -EINVAL;
115 }
116
xpm_get_process_cs_info(struct cs_info * pcs_info)117 int xpm_get_process_cs_info(struct cs_info *pcs_info)
118 {
119 int ret;
120 struct exec_file_signature_info *info = NULL;
121 struct file *exe_file = NULL;
122 struct cs_info fcs_info = {0};
123 struct mm_struct *mm = current->mm;
124
125 if (!mm)
126 return -EINVAL;
127
128 /* process cs_info has not been init, just init from exe file */
129 if (mm->pcs_info.id_type == PROCESS_OWNERID_UNINIT) {
130 exe_file = get_task_exe_file(current);
131 if (!exe_file) {
132 xpm_log_error("xpm get exe_file failed");
133 return -ENOEXEC;
134 }
135
136 ret = get_exec_file_signature_info(exe_file, true, &info);
137 /* reduce exe_file reference count */
138 fput(exe_file);
139 if (ret || (info == NULL)) {
140 xpm_log_error("xpm get exe_file signature info failed");
141 return ret;
142 }
143
144 ret = xpm_get_file_cs_info(&fcs_info, info);
145 if (ret) {
146 xpm_log_error("xpm get exe_file cs info failed");
147 return ret;
148 }
149
150 /* process's ownerid is correspond to file */
151 mm->pcs_info.id_type = fcs_info.id_type;
152 mm->pcs_info.ownerid = fcs_info.ownerid;
153 }
154 pcs_info->id_type = mm->pcs_info.id_type;
155 pcs_info->ownerid = mm->pcs_info.ownerid;
156
157 return 0;
158 }
159
xpm_check_ownerid(struct vm_area_struct * vma,struct exec_file_signature_info * info)160 static int xpm_check_ownerid(struct vm_area_struct *vma,
161 struct exec_file_signature_info *info)
162 {
163 int ret;
164 struct cs_info pcs_info = {0};
165 struct cs_info fcs_info = {0};
166
167 ret = xpm_get_process_cs_info(&pcs_info);
168 if (ret) {
169 xpm_log_error("xpm get process cs_info falied");
170 return ret;
171 }
172
173 ret = xpm_get_file_cs_info(&fcs_info, info);
174 if (ret) {
175 xpm_log_error("xpm get file cs_info falied");
176 return ret;
177 }
178
179 return xpm_check_ownerid_policy(&pcs_info, &fcs_info);
180 }
181
xpm_avc_has_perm(u16 tclass,u32 requested)182 static int xpm_avc_has_perm(u16 tclass, u32 requested)
183 {
184 struct av_decision avd;
185 u32 sid = current_sid();
186
187 #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0))
188 return avc_has_perm_noaudit(&selinux_state, sid, sid, tclass, requested,
189 AVC_STRICT, &avd);
190 #else
191 return avc_has_perm_noaudit(sid, sid, tclass, requested,
192 AVC_STRICT, &avd);
193 #endif
194 }
195
xpm_validate_signature(struct vm_area_struct * vma,struct exec_file_signature_info * info)196 static int xpm_validate_signature(struct vm_area_struct *vma,
197 struct exec_file_signature_info *info)
198 {
199 unsigned long verified_data_end, vm_addr_end;
200 const struct inode *inode = (const struct inode *)info->inode;
201
202 if (IS_ERR_OR_NULL(info)) {
203 xpm_log_error("signature info is NULL");
204 return -EPERM;
205 }
206
207 if(!exec_file_signature_is_fs_verity(info))
208 return 0;
209
210 vm_addr_end = (vma->vm_pgoff << PAGE_SHIFT)
211 + (vma->vm_end - vma->vm_start);
212 verified_data_end = PAGE_ALIGN(fsverity_get_verified_data_size(inode));
213 if (verified_data_end < vm_addr_end) {
214 xpm_log_error("data is out of verified data size");
215 return -EPERM;
216 }
217
218 return 0;
219 }
220
xpm_check_code_segment(bool is_exec,struct vm_area_struct * vma,struct exec_file_signature_info * info)221 static int xpm_check_code_segment(bool is_exec, struct vm_area_struct *vma,
222 struct exec_file_signature_info *info)
223 {
224 int i;
225 unsigned long vm_addr_start, vm_addr_end;
226 unsigned long seg_addr_start, seg_addr_end;
227 struct exec_segment_info *segments = info->code_segments;
228
229 if (!is_exec)
230 return 0;
231
232 if (!segments) {
233 xpm_log_error("code segments is NULL");
234 return -EINVAL;
235 }
236
237 vm_addr_start = vma->vm_pgoff << PAGE_SHIFT;
238 vm_addr_end = vm_addr_start + (vma->vm_end - vma->vm_start);
239
240 for (i = 0; i < info->code_segment_count; i++) {
241 seg_addr_start = ALIGN_DOWN(segments[i].file_offset, PAGE_SIZE);
242 seg_addr_end = PAGE_ALIGN(segments[i].file_offset +
243 segments[i].size);
244 if ((vm_addr_start >= seg_addr_start) &&
245 (vm_addr_end <= seg_addr_end))
246 return 0;
247 }
248
249 return -EPERM;
250 }
251
xpm_check_signature(struct vm_area_struct * vma,unsigned long prot)252 static int xpm_check_signature(struct vm_area_struct *vma, unsigned long prot)
253 {
254 int ret;
255 bool is_exec;
256 struct exec_file_signature_info *info = NULL;
257
258 /* vma is non-executable or mmap in xpm region just return */
259 is_exec = !xpm_is_anonymous_vma(vma) && (prot & PROT_EXEC);
260 if (!((vma->vm_flags & VM_XPM) || is_exec))
261 return 0;
262
263 /* process has exec_no_sign permission just return */
264 if (xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_NO_SIGN) == 0)
265 return 0;
266
267 /* validate signature when vma is mmap in xpm region or executable */
268 ret = get_exec_file_signature_info(vma->vm_file, is_exec, &info);
269 if (ret) {
270 report_mmap_event(GET_SIGN_FAIL, is_exec ? TYPE_ELF : TYPE_ABC,
271 vma, prot);
272 return ret;
273 }
274
275 do {
276 ret = xpm_validate_signature(vma, info);
277 if (ret) {
278 report_mmap_event(SIGN_INVALID,
279 is_exec ? TYPE_ELF : TYPE_ABC, vma, prot);
280 break;
281 }
282
283 ret = xpm_check_code_segment(is_exec, vma, info);
284 if (ret) {
285 report_mmap_event(DATA_MMAP_CODE,
286 is_exec ? TYPE_ELF : TYPE_ABC, vma, prot);
287 break;
288 }
289
290 ret = xpm_check_ownerid(vma, info);
291 if (ret) {
292 report_mmap_event(OWNERID_INCONSISTENT,
293 is_exec ? TYPE_ELF : TYPE_ABC, vma, prot);
294 break;
295 }
296 } while (0);
297
298 if (info)
299 put_exec_file_signature_info(info);
300
301 return ret;
302 }
303
xpm_check_prot(struct vm_area_struct * vma,unsigned long prot)304 static int xpm_check_prot(struct vm_area_struct *vma, unsigned long prot)
305 {
306 int ret;
307 bool is_anon;
308
309 is_anon = xpm_is_anonymous_vma(vma);
310
311 /* check for xpm region vma prot */
312 if (vma->vm_flags & VM_XPM) {
313 if (is_anon || (prot & PROT_EXEC)) {
314 xpm_log_error("xpm region mmap not allow anonymous or exec permission");
315 return -EPERM;
316 }
317
318 return 0;
319 }
320
321 /* check for anonymous vma prot, anonymous executable permission need
322 * controled by selinux
323 * in secure shield mode, all anon + x is forbidden
324 * in default mode, temporarily allow anon + x allocation
325 */
326 if (vma_is_anonymous(vma) && (prot & PROT_EXEC)) {
327 if (dsmm_is_secureshield_enabled()) {
328 ret = -EPERM;
329 report_mmap_event(ANON_EXEC, TYPE_ANON, vma, prot);
330 } else {
331 ret = xpm_avc_has_perm(SECCLASS_XPM, XPM__EXEC_ANON_MEM);
332 if (ret) {
333 ret = 0;
334 report_mmap_event(ANON_EXEC, TYPE_ANON, vma, prot);
335 }
336 }
337
338 return ret;
339 }
340
341 /* check for non-anonymous vma prot */
342 if (!is_anon && (prot & PROT_WRITE) && (prot & PROT_EXEC)) {
343 xpm_log_error("file mmap not allow write & exec permission");
344 return -EPERM;
345 }
346
347 return 0;
348 }
349
xpm_common_check(struct vm_area_struct * vma,unsigned long prot)350 static int xpm_common_check(struct vm_area_struct *vma, unsigned long prot)
351 {
352 int ret;
353
354 do {
355 ret = xpm_check_prot(vma, prot);
356 if (ret)
357 break;
358
359 ret = xpm_check_signature(vma, prot);
360 } while (0);
361
362 return xpm_ret(ret);
363 }
364
xpm_mmap_check(struct vm_area_struct * vma)365 static int xpm_mmap_check(struct vm_area_struct *vma)
366 {
367 return xpm_common_check(vma, vma->vm_flags);
368 }
369
xpm_mprotect_check(struct vm_area_struct * vma,unsigned long reqprot,unsigned long prot)370 static int xpm_mprotect_check(struct vm_area_struct *vma,
371 unsigned long reqprot, unsigned long prot)
372 {
373 (void)reqprot;
374
375 return xpm_common_check(vma, prot);
376 }
377
378 static struct security_hook_list xpm_hooks[] __ro_after_init = {
379 LSM_HOOK_INIT(mmap_region, xpm_mmap_check),
380 LSM_HOOK_INIT(file_mprotect, xpm_mprotect_check),
381 };
382
xpm_register_security_hooks(void)383 void xpm_register_security_hooks(void)
384 {
385 init_ownerid_policy();
386 security_add_hooks(xpm_hooks, ARRAY_SIZE(xpm_hooks), "xpm");
387 }
388