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