• 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/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