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 14struct 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 31void 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 42const 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 59const 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 152int 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 171void 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 177const 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 204void 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 213int 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 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 254static __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 322static __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 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 349void 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 360void 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 455void 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