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 dentry * dentry)360 void check_and_fixup_ownership_remote(struct inode *dir,
361 struct dentry *dentry)
362 {
363 struct hmdfs_inode_info *hii = hmdfs_i(dir);
364 struct inode *dinode = d_inode(dentry);
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 hmdfs_debug("level:0x%X", level);
370 switch (level) {
371 case HMDFS_PERM_MNT:
372 /* system : media_rw */
373 dinode->i_uid = USER_DATA_RW_UID;
374 dinode->i_gid = USER_DATA_RW_GID;
375 perm = (hii->perm & HMDFS_DIR_TYPE_MASK) | level;
376 break;
377 case HMDFS_PERM_DFS:
378 /*
379 * data : system : media_rw
380 * system: system : media_rw, need authority
381 * other : media_rw : media_rw
382 **/
383 if (!strcmp(dentry->d_name.name, DFS_SHARE_NAME)) {
384 perm = HMDFS_DIR_SERVICES | level;
385 dinode->i_uid = DFS_SHARE_UID;
386 dinode->i_gid = DFS_SHARE_GID;
387 dinode->i_mode = dinode->i_mode | S_IRWXG;
388 break;
389 }
390 if (!strcmp(dentry->d_name.name, PKG_ROOT_NAME)) {
391 perm = HMDFS_DIR_DATA | level;
392 } else {
393 perm = HMDFS_DIR_PUBLIC | level;
394 }
395 dinode->i_uid = USER_DATA_RW_UID;
396 dinode->i_gid = USER_DATA_RW_GID;
397 break;
398 case HMDFS_PERM_PKG:
399 if (is_service_dir(hii->perm)) {
400 dinode->i_uid = DFS_SHARE_UID;
401 dinode->i_gid = DFS_SHARE_GID;
402 dinode->i_mode = dinode->i_mode | S_IRWXG;
403 perm = AUTH_SERVICES | HMDFS_DIR_PKG | level;
404 break;
405 }
406 if (is_data_dir(hii->perm)) {
407 /*
408 * Mkdir for app pkg.
409 * Get the appid by passing pkgname to configfs.
410 * Set ROOT + media_rw for remote install,
411 * local uninstall.
412 * Set appid + media_rw for local install.
413 */
414 int bid = get_bundle_uid(hmdfs_sb(dentry->d_sb),
415 dentry->d_name.name);
416 if (bid != 0) {
417 dinode->i_uid = KUIDT_INIT(bid);
418 dinode->i_gid = KGIDT_INIT(bid);
419 } else {
420 dinode->i_uid = ROOT_UID;
421 dinode->i_gid = ROOT_GID;
422 }
423 perm = AUTH_PKG | HMDFS_DIR_PKG | level;
424 } else {
425 dinode->i_uid = dir->i_uid;
426 dinode->i_gid = dir->i_gid;
427 perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
428 }
429 break;
430 case HMDFS_PERM_OTHER:
431 dinode->i_uid = dir->i_uid;
432 dinode->i_gid = dir->i_gid;
433 if (is_service_auth(hii->perm)) {
434 dinode->i_mode = dir->i_mode | S_IRWXG;
435 perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
436 break;
437 }
438 if (is_pkg_auth(hii->perm))
439 perm = AUTH_PKG | HMDFS_DIR_PKG_SUB | level;
440 else
441 perm = (hii->perm & AUTH_MASK) | HMDFS_DIR_DEFAULT | level;
442 break;
443 default:
444 /* ! it should not get to here */
445 hmdfs_err("hmdfs perm incorrect got default case, level:%u", level);
446 break;
447 }
448
449 dinfo->perm = perm;
450 }
451
hmdfs_root_inode_perm_init(struct inode * root_inode)452 void hmdfs_root_inode_perm_init(struct inode *root_inode)
453 {
454 struct hmdfs_inode_info *hii = hmdfs_i(root_inode);
455
456 hii->perm = HMDFS_DIR_ROOT | HMDFS_PERM_MNT;
457 set_inode_uid(root_inode, USER_DATA_RW_UID);
458 set_inode_gid(root_inode, USER_DATA_RW_GID);
459 }
460