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