• 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 		 * other : media_rw : media_rw
84 		 **/
85 		if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
86 			perm = HMDFS_DIR_DATA | level;
87 		} else {
88 			perm = HMDFS_DIR_PUBLIC | level;
89 		}
90 		cred->fsuid = USER_DATA_RW_UID;
91 		cred->fsgid = USER_DATA_RW_GID;
92 		break;
93 	case HMDFS_PERM_PKG:
94 		if (is_data_dir(hii->perm)) {
95 			/*
96 			 * Mkdir for app pkg.
97 			 * Get the appid by passing pkgname to configfs.
98 			 * Set ROOT + media_rw for remote install,
99 			 * local uninstall.
100 			 * Set appid + media_rw for local install.
101 			 */
102 			int bid = get_bundle_uid(hmdfs_sb(dentry->d_sb),
103 				dentry->d_name.name);
104 
105 			if (bid != 0) {
106 				cred->fsuid = KUIDT_INIT(bid);
107 				cred->fsgid = KGIDT_INIT(bid);
108 			} else {
109 				cred->fsuid = ROOT_UID;
110 				cred->fsgid = ROOT_GID;
111 			}
112 			perm = AUTH_PKG | HMDFS_DIR_PKG | level;
113 		} else {
114 			cred->fsuid = dir->i_uid;
115 			cred->fsgid = dir->i_gid;
116 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
117 		}
118 		break;
119 	case HMDFS_PERM_OTHER:
120 		cred->fsuid = dir->i_uid;
121 		cred->fsgid = dir->i_gid;
122 		if (is_pkg_auth(hii->perm))
123 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
124 		else
125 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
126 		break;
127 	default:
128 		/* ! it should not get to here */
129 		hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
130 		break;
131 	}
132 
133 	*_perm = perm;
134 	old_cred = override_creds(cred);
135 
136 	return old_cred;
137 }
138 
hmdfs_override_dir_id_fs(struct cache_fs_override * or,struct inode * dir,struct dentry * dentry,__u16 * perm)139 int hmdfs_override_dir_id_fs(struct cache_fs_override *or,
140 			struct inode *dir,
141 			struct dentry *dentry,
142 			__u16 *perm)
143 {
144 	or->saved_cred = hmdfs_override_dir_fsids(dir, dentry, perm);
145 	if (!or->saved_cred)
146 		return -ENOMEM;
147 
148 	or->saved_fs = current->fs;
149 	or->copied_fs = hmdfs_override_fsstruct(or->saved_fs);
150 	if (!or->copied_fs) {
151 		hmdfs_revert_fsids(or->saved_cred);
152 		return -ENOMEM;
153 	}
154 
155 	return 0;
156 }
157 
hmdfs_revert_dir_id_fs(struct cache_fs_override * or)158 void hmdfs_revert_dir_id_fs(struct cache_fs_override *or)
159 {
160 	hmdfs_revert_fsstruct(or->saved_fs, or->copied_fs);
161 	hmdfs_revert_fsids(or->saved_cred);
162 }
163 
hmdfs_override_file_fsids(struct inode * dir,__u16 * _perm)164 const struct cred *hmdfs_override_file_fsids(struct inode *dir, __u16 *_perm)
165 {
166 	struct hmdfs_inode_info *hii = hmdfs_i(dir);
167 	struct cred *cred = NULL;
168 	const struct cred *old_cred = NULL;
169 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
170 	uint16_t perm;
171 
172 	perm = HMDFS_FILE_DEFAULT | level;
173 
174 	cred = prepare_creds();
175 	if (!cred)
176 		return NULL;
177 
178 	cred->fsuid = dir->i_uid;
179 	cred->fsgid = dir->i_gid;
180 	if (is_pkg_auth(hii->perm))
181 		perm = AUTH_PKG | HMDFS_FILE_PKG_SUB | level;
182 	else
183 		perm = (hii->perm & AUTH_MASK) | HMDFS_FILE_DEFAULT | level;
184 
185 	*_perm = perm;
186 	old_cred = override_creds(cred);
187 
188 	return old_cred;
189 }
190 
hmdfs_revert_fsids(const struct cred * old_cred)191 void hmdfs_revert_fsids(const struct cred *old_cred)
192 {
193 	const struct cred *cur_cred;
194 
195 	cur_cred = current->cred;
196 	revert_creds(old_cred);
197 	put_cred(cur_cred);
198 }
199 
hmdfs_persist_perm(struct dentry * dentry,__u16 * perm)200 int hmdfs_persist_perm(struct dentry *dentry, __u16 *perm)
201 {
202 	int err;
203 	struct inode *minode = d_inode(dentry);
204 
205 	if (!minode)
206 		return -EINVAL;
207 
208 	inode_lock(minode);
209 	err = __vfs_setxattr(dentry, minode, HMDFS_PERM_XATTR, perm,
210 			     sizeof(*perm), XATTR_CREATE);
211 	if (!err)
212 		fsnotify_xattr(dentry);
213 	else if (err && err != -EEXIST)
214 		hmdfs_err("failed to setxattr, err=%d", err);
215 	inode_unlock(minode);
216 	return err;
217 }
218 
hmdfs_read_perm(struct inode * inode)219 __u16 hmdfs_read_perm(struct inode *inode)
220 {
221 	__u16 ret = 0;
222 	int size = 0;
223 	struct dentry *dentry = d_find_alias(inode);
224 
225 	if (!dentry)
226 		return ret;
227 
228 	size = __vfs_getxattr(dentry, inode, HMDFS_PERM_XATTR, &ret,
229 			     sizeof(ret));
230 	 /*
231 	  * some file may not set setxattr with perm
232 	  * eg. files created in sdcard dir by other user
233 	  **/
234 	if (size < 0 || size != sizeof(ret))
235 		ret = HMDFS_ALL_MASK;
236 
237 	dput(dentry);
238 	return ret;
239 }
240 
__inherit_perm_dir(struct inode * parent,struct inode * inode)241 static __u16 __inherit_perm_dir(struct inode *parent, struct inode *inode)
242 {
243 	__u16 perm = 0;
244 	struct hmdfs_inode_info *info = hmdfs_i(parent);
245 	__u16 level = hmdfs_perm_get_next_level(info->perm);
246 	struct dentry *dentry = d_find_alias(inode);
247 
248 	if (!dentry)
249 		return perm;
250 
251 	switch (level) {
252 	case HMDFS_PERM_MNT:
253 		/* system : media_rw */
254 		perm = (info->perm & HMDFS_DIR_TYPE_MASK) | level;
255 		break;
256 	case HMDFS_PERM_DFS:
257 		/*
258 		 * data  : system : media_rw
259 		 * system: system : media_rw, need authority
260 		 * other : media_rw : media_rw
261 		 **/
262 		if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
263 			// "data"
264 			perm = HMDFS_DIR_DATA | level;
265 		} else if (!strcmp(dentry->d_name.name, SYSTEM_NAME)) {
266 			 // "system"
267 			perm = AUTH_SYSTEM | HMDFS_DIR_SYSTEM | level;
268 		} else {
269 			perm = HMDFS_DIR_PUBLIC | level;
270 		}
271 		break;
272 	case HMDFS_PERM_PKG:
273 		if (is_data_dir(info->perm)) {
274 			/*
275 			 * Mkdir for app pkg.
276 			 * Get the appid by passing pkgname to configfs.
277 			 * Set ROOT + media_rw for remote install,
278 			 * local uninstall.
279 			 * Set appid + media_rw for local install.
280 			 */
281 			perm = AUTH_PKG | HMDFS_DIR_PKG | level;
282 		} else {
283 			perm = (info->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
284 		}
285 		break;
286 	case HMDFS_PERM_OTHER:
287 		if (is_pkg_auth(info->perm))
288 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
289 		else
290 			perm = (info->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
291 		break;
292 	default:
293 		/* ! it should not get to here */
294 		hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
295 		break;
296 	}
297 	dput(dentry);
298 	return perm;
299 }
300 
__inherit_perm_file(struct inode * parent)301 static __u16 __inherit_perm_file(struct inode *parent)
302 {
303 	struct hmdfs_inode_info *hii = hmdfs_i(parent);
304 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
305 	uint16_t perm;
306 
307 	perm = HMDFS_FILE_DEFAULT | level;
308 
309 	if (is_pkg_auth(hii->perm))
310 		perm = AUTH_PKG | HMDFS_FILE_PKG_SUB | level;
311 	else
312 		perm = (hii->perm & AUTH_MASK) | HMDFS_FILE_DEFAULT | level;
313 
314 	return perm;
315 }
316 
hmdfs_perm_inherit(struct inode * parent_inode,struct inode * child)317 __u16 hmdfs_perm_inherit(struct inode *parent_inode, struct inode *child)
318 {
319 	__u16 perm;
320 
321 	if (S_ISDIR(child->i_mode))
322 		perm = __inherit_perm_dir(parent_inode, child);
323 	else
324 		perm = __inherit_perm_file(parent_inode);
325 	return perm;
326 }
327 
check_and_fixup_ownership(struct inode * parent_inode,struct inode * child)328 void check_and_fixup_ownership(struct inode *parent_inode, struct inode *child)
329 {
330 	struct hmdfs_inode_info *info = hmdfs_i(child);
331 
332 	if (info->perm == HMDFS_ALL_MASK)
333 		info->perm = hmdfs_perm_inherit(parent_inode, child);
334 }
335 
check_and_fixup_ownership_remote(struct inode * dir,struct dentry * dentry)336 void check_and_fixup_ownership_remote(struct inode *dir,
337 				      struct dentry *dentry)
338 {
339 	struct hmdfs_inode_info *hii = hmdfs_i(dir);
340 	struct inode *dinode = d_inode(dentry);
341 	struct hmdfs_inode_info *dinfo = hmdfs_i(dinode);
342 	__u16 level = hmdfs_perm_get_next_level(hii->perm);
343 	__u16 perm = 0;
344 
345 	hmdfs_debug("level:0x%X", level);
346 	switch (level) {
347 	case HMDFS_PERM_MNT:
348 		/* system : media_rw */
349 		dinode->i_uid = USER_DATA_RW_UID;
350 		dinode->i_gid = USER_DATA_RW_GID;
351 		perm = (hii->perm & HMDFS_DIR_TYPE_MASK) | level;
352 		break;
353 	case HMDFS_PERM_DFS:
354 		/*
355 		 * data  : system : media_rw
356 		 * system: system : media_rw, need authority
357 		 * other : media_rw : media_rw
358 		 **/
359 		if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
360 			perm = HMDFS_DIR_DATA | level;
361 		} else {
362 			perm = HMDFS_DIR_PUBLIC | level;
363 		}
364 		dinode->i_uid = USER_DATA_RW_UID;
365 		dinode->i_gid = USER_DATA_RW_GID;
366 		break;
367 	case HMDFS_PERM_PKG:
368 		if (is_data_dir(hii->perm)) {
369 			/*
370 			 * Mkdir for app pkg.
371 			 * Get the appid by passing pkgname to configfs.
372 			 * Set ROOT + media_rw for remote install,
373 			 * local uninstall.
374 			 * Set appid + media_rw for local install.
375 			 */
376 			int bid = get_bundle_uid(hmdfs_sb(dentry->d_sb),
377 				dentry->d_name.name);
378 			if (bid != 0) {
379 				dinode->i_uid = KUIDT_INIT(bid);
380 				dinode->i_gid = KGIDT_INIT(bid);
381 			} else {
382 				dinode->i_uid = ROOT_UID;
383 				dinode->i_gid = ROOT_GID;
384 			}
385 			perm = AUTH_PKG | HMDFS_DIR_PKG | level;
386 		} else {
387 			dinode->i_uid = dir->i_uid;
388 			dinode->i_gid = dir->i_gid;
389 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
390 		}
391 		break;
392 	case HMDFS_PERM_OTHER:
393 		dinode->i_uid = dir->i_uid;
394 		dinode->i_gid = dir->i_gid;
395 		if (is_pkg_auth(hii->perm))
396 			perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
397 		else
398 			perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
399 		break;
400 	default:
401 		/* ! it should not get to here */
402 		hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
403 		break;
404 	}
405 
406 	dinfo->perm = perm;
407 }
408 
hmdfs_root_inode_perm_init(struct inode * root_inode)409 void hmdfs_root_inode_perm_init(struct inode *root_inode)
410 {
411 	struct hmdfs_inode_info *hii = hmdfs_i(root_inode);
412 
413 	hii->perm = HMDFS_DIR_ROOT | HMDFS_PERM_MNT;
414 	set_inode_uid(root_inode, USER_DATA_RW_UID);
415 	set_inode_gid(root_inode, USER_DATA_RW_GID);
416 }
417