• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fs/hmdfs/comm/authority/authentication.c
4  *
5  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6  */
7 
8 #include "authentication.h"
9 #include <linux/fsnotify.h>
10 #include <linux/security.h>
11 
12 #include "hmdfs.h"
13 
hmdfs_override_fsstruct(struct fs_struct * saved_fs)14 struct fs_struct *hmdfs_override_fsstruct(struct fs_struct *saved_fs)
15 {
16 #if (defined CONFIG_HMDFS_FS_PERMISSION) && (defined CONFIG_SDCARD_FS)
17 	struct fs_struct *copied_fs = copy_fs_struct(saved_fs);
18 
19 	if (!copied_fs)
20 		return NULL;
21 	copied_fs->umask = 0;
22 	task_lock(current);
23 	current->fs = copied_fs;
24 	task_unlock(current);
25 	return copied_fs;
26 #else
27 	return saved_fs;
28 #endif
29 }
30 
hmdfs_revert_fsstruct(struct fs_struct * saved_fs,struct fs_struct * copied_fs)31 void hmdfs_revert_fsstruct(struct fs_struct *saved_fs,
32 			   struct fs_struct *copied_fs)
33 {
34 #if (defined CONFIG_HMDFS_FS_PERMISSION) && (defined CONFIG_SDCARD_FS)
35 	task_lock(current);
36 	current->fs = saved_fs;
37 	task_unlock(current);
38 	free_fs_struct(copied_fs);
39 #endif
40 }
41 
hmdfs_override_fsids(bool is_recv_thread)42 const struct cred *hmdfs_override_fsids(bool is_recv_thread)
43 {
44 	struct cred *cred = NULL;
45 	const struct cred *old_cred = NULL;
46 
47 	cred = prepare_creds();
48 	if (!cred)
49 		return NULL;
50 
51 	cred->fsuid = is_recv_thread ? SYSTEM_UID : USER_DATA_RW_UID;
52 	cred->fsgid = is_recv_thread ? SYSTEM_GID : USER_DATA_RW_GID;
53 
54 	old_cred = override_creds(cred);
55 
56 	return old_cred;
57 }
58 
hmdfs_override_dir_fsids(struct inode * dir,struct dentry * dentry,__u16 * _perm)59 const struct cred *hmdfs_override_dir_fsids(struct inode *dir,
60 					    struct dentry *dentry, __u16 *_perm)
61 {
62 	struct hmdfs_inode_info *hii = hmdfs_i(dir);
63 	struct cred *cred = NULL;
64 	const struct cred *old_cred = NULL;
65 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
66 	__u16 perm = 0;
67 
68 	cred = prepare_creds();
69 	if (!cred)
70 		return NULL;
71 
72 	switch (level) {
73 	case HMDFS_PERM_MNT:
74 		/* system : media_rw */
75 		cred->fsuid = USER_DATA_RW_UID;
76 		cred->fsgid = USER_DATA_RW_GID;
77 		perm = (hii->perm & HMDFS_DIR_TYPE_MASK) | level;
78 		break;
79 	case HMDFS_PERM_DFS:
80 		/*
81 		 * data  : system : media_rw
82 		 * system: system : media_rw, need authority
83 		 * services: dfs_share : dfs_share
84 		 * other : media_rw : media_rw
85 		 **/
86 		if (!strcmp(dentry->d_name.name, DFS_SHARE_NAME)) {
87 			perm = HMDFS_DIR_SERVICES | level;
88 			cred->fsuid = DFS_SHARE_UID;
89 			cred->fsgid = DFS_SHARE_GID;
90 			break;
91 		}
92 		if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
93 			perm = HMDFS_DIR_DATA | level;
94 		} else {
95 			perm = HMDFS_DIR_PUBLIC | level;
96 		}
97 		cred->fsuid = USER_DATA_RW_UID;
98 		cred->fsgid = USER_DATA_RW_GID;
99 		break;
100 	case HMDFS_PERM_PKG:
101 		if (is_service_dir(hii->perm)) {
102 			cred->fsuid = DFS_SHARE_UID;
103 			cred->fsgid = DFS_SHARE_GID;
104 			perm = AUTH_SERVICES | HMDFS_DIR_PKG | level;
105 			break;
106 		}
107 		if (is_data_dir(hii->perm)) {
108 			/*
109 			 * Mkdir for app pkg.
110 			 * Get the appid by passing pkgname to configfs.
111 			 * Set ROOT + media_rw for remote install,
112 			 * local uninstall.
113 			 * Set appid + media_rw for local install.
114 			 */
115 			int bid = get_bundle_uid(hmdfs_sb(dentry->d_sb),
116 				dentry->d_name.name);
117 
118 			if (bid != 0) {
119 				cred->fsuid = KUIDT_INIT(bid);
120 				cred->fsgid = KGIDT_INIT(bid);
121 			} else {
122 				cred->fsuid = ROOT_UID;
123 				cred->fsgid = ROOT_GID;
124 			}
125 			perm = AUTH_PKG | HMDFS_DIR_PKG | level;
126 		} else {
127 			cred->fsuid = dir->i_uid;
128 			cred->fsgid = dir->i_gid;
129 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
130 		}
131 		break;
132 	case HMDFS_PERM_OTHER:
133 		cred->fsuid = dir->i_uid;
134 		cred->fsgid = dir->i_gid;
135 		if (is_pkg_auth(hii->perm))
136 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
137 		else
138 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
139 		break;
140 	default:
141 		/* ! it should not get to here */
142 		hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
143 		break;
144 	}
145 
146 	*_perm = perm;
147 	old_cred = override_creds(cred);
148 
149 	return old_cred;
150 }
151 
hmdfs_override_dir_id_fs(struct cache_fs_override * or,struct inode * dir,struct dentry * dentry,__u16 * perm)152 int hmdfs_override_dir_id_fs(struct cache_fs_override *or,
153 			struct inode *dir,
154 			struct dentry *dentry,
155 			__u16 *perm)
156 {
157 	or->saved_cred = hmdfs_override_dir_fsids(dir, dentry, perm);
158 	if (!or->saved_cred)
159 		return -ENOMEM;
160 
161 	or->saved_fs = current->fs;
162 	or->copied_fs = hmdfs_override_fsstruct(or->saved_fs);
163 	if (!or->copied_fs) {
164 		hmdfs_revert_fsids(or->saved_cred);
165 		return -ENOMEM;
166 	}
167 
168 	return 0;
169 }
170 
hmdfs_revert_dir_id_fs(struct cache_fs_override * or)171 void hmdfs_revert_dir_id_fs(struct cache_fs_override *or)
172 {
173 	hmdfs_revert_fsstruct(or->saved_fs, or->copied_fs);
174 	hmdfs_revert_fsids(or->saved_cred);
175 }
176 
hmdfs_override_file_fsids(struct inode * dir,__u16 * _perm)177 const struct cred *hmdfs_override_file_fsids(struct inode *dir, __u16 *_perm)
178 {
179 	struct hmdfs_inode_info *hii = hmdfs_i(dir);
180 	struct cred *cred = NULL;
181 	const struct cred *old_cred = NULL;
182 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
183 	uint16_t perm;
184 
185 	perm = HMDFS_FILE_DEFAULT | level;
186 
187 	cred = prepare_creds();
188 	if (!cred)
189 		return NULL;
190 
191 	cred->fsuid = dir->i_uid;
192 	cred->fsgid = dir->i_gid;
193 	if (is_pkg_auth(hii->perm))
194 		perm = AUTH_PKG | HMDFS_FILE_PKG_SUB | level;
195 	else
196 		perm = (hii->perm & AUTH_MASK) | HMDFS_FILE_DEFAULT | level;
197 
198 	*_perm = perm;
199 	old_cred = override_creds(cred);
200 
201 	return old_cred;
202 }
203 
hmdfs_revert_fsids(const struct cred * old_cred)204 void hmdfs_revert_fsids(const struct cred *old_cred)
205 {
206 	const struct cred *cur_cred;
207 
208 	cur_cred = current->cred;
209 	revert_creds(old_cred);
210 	put_cred(cur_cred);
211 }
212 
hmdfs_persist_perm(struct dentry * dentry,__u16 * perm)213 int hmdfs_persist_perm(struct dentry *dentry, __u16 *perm)
214 {
215 	int err;
216 	struct inode *minode = d_inode(dentry);
217 
218 	if (!minode)
219 		return -EINVAL;
220 
221 	inode_lock(minode);
222 	err = __vfs_setxattr(dentry, minode, HMDFS_PERM_XATTR, perm,
223 			     sizeof(*perm), XATTR_CREATE);
224 	if (!err)
225 		fsnotify_xattr(dentry);
226 	else if (err && err != -EEXIST)
227 		hmdfs_err("failed to setxattr, err=%d", err);
228 	inode_unlock(minode);
229 	return err;
230 }
231 
hmdfs_read_perm(struct inode * inode)232 __u16 hmdfs_read_perm(struct inode *inode)
233 {
234 	__u16 ret = 0;
235 	int size = 0;
236 	struct dentry *dentry = d_find_alias(inode);
237 
238 	if (!dentry)
239 		return ret;
240 
241 	size = __vfs_getxattr(dentry, inode, HMDFS_PERM_XATTR, &ret,
242 			     sizeof(ret));
243 	 /*
244 	  * some file may not set setxattr with perm
245 	  * eg. files created in sdcard dir by other user
246 	  **/
247 	if (size < 0 || size != sizeof(ret))
248 		ret = HMDFS_ALL_MASK;
249 
250 	dput(dentry);
251 	return ret;
252 }
253 
__inherit_perm_dir(struct inode * parent,struct inode * inode)254 static __u16 __inherit_perm_dir(struct inode *parent, struct inode *inode)
255 {
256 	__u16 perm = 0;
257 	struct hmdfs_inode_info *info = hmdfs_i(parent);
258 	__u16 level = hmdfs_perm_get_next_level(info->perm);
259 	struct dentry *dentry = d_find_alias(inode);
260 
261 	if (!dentry)
262 		return perm;
263 
264 	switch (level) {
265 	case HMDFS_PERM_MNT:
266 		/* system : media_rw */
267 		perm = (info->perm & HMDFS_DIR_TYPE_MASK) | level;
268 		break;
269 	case HMDFS_PERM_DFS:
270 		/*
271 		 * data  : system : media_rw
272 		 * system: system : media_rw, need authority
273 		 * services: dfs_share : dfs_share
274 		 * other : media_rw : media_rw
275 		 **/
276 		if (!strcmp(dentry->d_name.name, DFS_SHARE_NAME)) {
277 			// "services"
278 			perm = HMDFS_DIR_SERVICES | level;
279 		} else if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
280 			// "data"
281 			perm = HMDFS_DIR_DATA | level;
282 		} else if (!strcmp(dentry->d_name.name, SYSTEM_NAME)) {
283 			 // "system"
284 			perm = AUTH_SYSTEM | HMDFS_DIR_SYSTEM | level;
285 		} else {
286 			perm = HMDFS_DIR_PUBLIC | level;
287 		}
288 		break;
289 	case HMDFS_PERM_PKG:
290 		if (is_service_dir(info->perm)) {
291 			perm = AUTH_SERVICES | HMDFS_DIR_PKG | level;
292 			break;
293 		}
294 		if (is_data_dir(info->perm)) {
295 			/*
296 			 * Mkdir for app pkg.
297 			 * Get the appid by passing pkgname to configfs.
298 			 * Set ROOT + media_rw for remote install,
299 			 * local uninstall.
300 			 * Set appid + media_rw for local install.
301 			 */
302 			perm = AUTH_PKG | HMDFS_DIR_PKG | level;
303 		} else {
304 			perm = (info->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
305 		}
306 		break;
307 	case HMDFS_PERM_OTHER:
308 		if (is_pkg_auth(info->perm))
309 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
310 		else
311 			perm = (info->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
312 		break;
313 	default:
314 		/* ! it should not get to here */
315 		hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
316 		break;
317 	}
318 	dput(dentry);
319 	return perm;
320 }
321 
__inherit_perm_file(struct inode * parent)322 static __u16 __inherit_perm_file(struct inode *parent)
323 {
324 	struct hmdfs_inode_info *hii = hmdfs_i(parent);
325 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
326 	uint16_t perm;
327 
328 	perm = HMDFS_FILE_DEFAULT | level;
329 
330 	if (is_pkg_auth(hii->perm))
331 		perm = AUTH_PKG | HMDFS_FILE_PKG_SUB | level;
332 	else
333 		perm = (hii->perm & AUTH_MASK) | HMDFS_FILE_DEFAULT | level;
334 
335 	return perm;
336 }
337 
hmdfs_perm_inherit(struct inode * parent_inode,struct inode * child)338 __u16 hmdfs_perm_inherit(struct inode *parent_inode, struct inode *child)
339 {
340 	__u16 perm;
341 
342 	if (S_ISDIR(child->i_mode))
343 		perm = __inherit_perm_dir(parent_inode, child);
344 	else
345 		perm = __inherit_perm_file(parent_inode);
346 	return perm;
347 }
348 
check_and_fixup_ownership(struct inode * parent_inode,struct inode * child)349 void check_and_fixup_ownership(struct inode *parent_inode, struct inode *child)
350 {
351 	struct hmdfs_inode_info *info = hmdfs_i(child);
352 	struct hmdfs_inode_info *dir = hmdfs_i(parent_inode);
353 
354 	if (info->perm == HMDFS_ALL_MASK)
355 		info->perm = hmdfs_perm_inherit(parent_inode, child);
356 	if (is_service_dir(dir->perm))
357 		child->i_mode = child->i_mode | S_IRWXG;
358 }
359 
check_and_fixup_ownership_remote(struct inode * dir,struct inode * dinode,struct dentry * dentry)360 void check_and_fixup_ownership_remote(struct inode *dir,
361 				      struct inode *dinode,
362 				      struct dentry *dentry)
363 {
364 	struct hmdfs_inode_info *hii = hmdfs_i(dir);
365 	struct hmdfs_inode_info *dinfo = hmdfs_i(dinode);
366 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
367 	__u16 perm = 0;
368 
369 	if (IS_ERR_OR_NULL(dinode))
370 		return;
371 
372 	hmdfs_debug("level:0x%X", level);
373 	switch (level) {
374 	case HMDFS_PERM_MNT:
375 		/* system : media_rw */
376 		dinode->i_uid = USER_DATA_RW_UID;
377 		dinode->i_gid = USER_DATA_RW_GID;
378 		perm = (hii->perm & HMDFS_DIR_TYPE_MASK) | level;
379 		break;
380 	case HMDFS_PERM_DFS:
381 		/*
382 		 * data  : system : media_rw
383 		 * system: system : media_rw, need authority
384 		 * other : media_rw : media_rw
385 		 **/
386 		if (!strcmp(dentry->d_name.name, DFS_SHARE_NAME)) {
387 			perm = HMDFS_DIR_SERVICES | level;
388 			dinode->i_uid = DFS_SHARE_UID;
389 			dinode->i_gid = DFS_SHARE_GID;
390 			dinode->i_mode = dinode->i_mode | S_IRWXG;
391 			break;
392 		}
393 		if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
394 			perm = HMDFS_DIR_DATA | level;
395 		} else {
396 			perm = HMDFS_DIR_PUBLIC | level;
397 		}
398 		dinode->i_uid = USER_DATA_RW_UID;
399 		dinode->i_gid = USER_DATA_RW_GID;
400 		break;
401 	case HMDFS_PERM_PKG:
402 		if (is_service_dir(hii->perm)) {
403 			dinode->i_uid = DFS_SHARE_UID;
404 			dinode->i_gid = DFS_SHARE_GID;
405 			dinode->i_mode = dinode->i_mode | S_IRWXG;
406 			perm = AUTH_SERVICES | HMDFS_DIR_PKG | level;
407 			break;
408 		}
409 		if (is_data_dir(hii->perm)) {
410 			/*
411 			 * Mkdir for app pkg.
412 			 * Get the appid by passing pkgname to configfs.
413 			 * Set ROOT + media_rw for remote install,
414 			 * local uninstall.
415 			 * Set appid + media_rw for local install.
416 			 */
417 			int bid = get_bundle_uid(hmdfs_sb(dentry->d_sb),
418 				dentry->d_name.name);
419 			if (bid != 0) {
420 				dinode->i_uid = KUIDT_INIT(bid);
421 				dinode->i_gid = KGIDT_INIT(bid);
422 			} else {
423 				dinode->i_uid = ROOT_UID;
424 				dinode->i_gid = ROOT_GID;
425 			}
426 			perm = AUTH_PKG | HMDFS_DIR_PKG | level;
427 		} else {
428 			dinode->i_uid = dir->i_uid;
429 			dinode->i_gid = dir->i_gid;
430 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
431 		}
432 		break;
433 	case HMDFS_PERM_OTHER:
434 		dinode->i_uid = dir->i_uid;
435 		dinode->i_gid = dir->i_gid;
436 		if (is_service_auth(hii->perm)) {
437 			dinode->i_mode = dir->i_mode | S_IRWXG;
438 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
439 			break;
440 		}
441 		if (is_pkg_auth(hii->perm))
442 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
443 		else
444 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
445 		break;
446 	default:
447 		/* ! it should not get to here */
448 		hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
449 		break;
450 	}
451 
452 	dinfo->perm = perm;
453 }
454 
hmdfs_root_inode_perm_init(struct inode * root_inode)455 void hmdfs_root_inode_perm_init(struct inode *root_inode)
456 {
457 	struct hmdfs_inode_info *hii = hmdfs_i(root_inode);
458 
459 	hii->perm = HMDFS_DIR_ROOT | HMDFS_PERM_MNT;
460 	set_inode_uid(root_inode, USER_DATA_RW_UID);
461 	set_inode_gid(root_inode, USER_DATA_RW_GID);
462 }
463