gid_t multiuser_get_ext_cache_gid(userid_t user_id, appid_t app_id) { if (app_id >= AID_APP_START && app_id <= AID_APP_END) { return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_CACHE_GID_START); } else { return -1; } }
void setup_derived_state_for_multiuser_gid(struct inode *inode, perm_t perm, userid_t userid, uid_t uid, gid_t gid, bool under_android) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); setup_derived_state(inode, perm, userid, uid, gid, under_android); info->d_gid = multiuser_get_uid(userid, gid); }
void get_derived_permission(struct dentry *parent, struct dentry *dentry) { struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); appid_t appid; /* By default, each inode inherits from its parent. * the properties are maintained on its private fields * because the inode attributes will be modified with that of * its lower inode. * The derived state will be updated on the last * stage of each system call by fix_derived_permission(inode). */ inherit_derived_state(parent->d_inode, dentry->d_inode); /* Derive custom permissions based on parent and current node */ switch (parent_info->perm) { case PERM_INHERIT: /* Already inherited above */ break; case PERM_PRE_ROOT: /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); if (sbi->options.sdfs_gid == AID_SDCARD_RW) info->d_gid = sbi->options.sdfs_gid; else info->d_gid = multiuser_get_uid(info->userid, sbi->options.sdfs_gid); break; case PERM_ROOT: /* Assume masked off by default. */ if (!strcasecmp(dentry->d_name.name, "Android")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->d_under_android = true; } break; case PERM_ANDROID: if (!strcasecmp(dentry->d_name.name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; } else if (!strcasecmp(dentry->d_name.name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; // FIXME : this feature will be implemented later. /* Single OBB directory is always shared */ // ex. Fuse daemon.. // node->graft_path = fuse->obb_path; // node->graft_pathlen = strlen(fuse->obb_path); } else if (!strcasecmp(dentry->d_name.name, "media")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; } break; /* same policy will be applied on PERM_ANDROID_DATA * and PERM_ANDROID_OBB */ case PERM_ANDROID_DATA: case PERM_ANDROID_OBB: case PERM_ANDROID_MEDIA: appid = get_appid(sbi->pkgl_id, dentry->d_name.name); if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } break; } }
/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = __d_alloc(sb, &name); if (ret) { d_set_d_op(ret, &sdcardfs_ci_dops); ret->d_parent = ret; } } return ret; } /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, void *raw_data, int silent) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; void *pkgl_id; printk(KERN_INFO "sdcardfs version %s\n", SDCARDFS_VERSION); if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { printk(KERN_ERR "sdcardfs: error accessing " "lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } sb_info = sb->s_fs_info; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options or out of memory\n"); goto out_freesbi; } pkgl_id = packagelist_create((char *)dev_name); if(IS_ERR(pkgl_id)) goto out_freesbi; else sb_info->pkgl_id = pkgl_id; /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_magic = SDCARDFS_SUPER_MAGIC; sb->s_op = &sdcardfs_sops; /* see comment next to the definition of sdcardfs_d_alloc_root */ sb->s_root = sdcardfs_d_alloc_root(sb); if (!sb->s_root) { err = -ENOMEM; goto out_sput; } /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* call interpose to create the upper level inode */ err = sdcardfs_interpose(sb->s_root, sb, &lower_path); if (!err) { /* setup permission policy */ if (sb_info->options.multi_user) { setup_derived_state_for_multiuser_gid(sb->s_root->d_inode, PERM_PRE_ROOT, 0, AID_ROOT, multiuser_get_uid(0,sb_info->options.sdfs_gid), false); sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); } else { setup_derived_state(sb->s_root->d_inode, PERM_ROOT, 0, AID_ROOT, multiuser_get_uid(0, sb_info->options.sdfs_gid), false); sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode, sb_info->options.sdfs_mask); if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; } /* else error: fall through */ free_dentry_private_data(sb->s_root); out_freeroot: dput(sb->s_root); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); packagelist_destroy(sb_info->pkgl_id); out_freesbi: kfree(SDCARDFS_SB(sb)); sb->s_fs_info = NULL; out_free: path_put(&lower_path); out: return err; }
static int initialize_directories() { int res = -1; // Read current filesystem layout version to handle upgrade paths char version_path[PATH_MAX]; snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str()); int oldVersion; if (fs_read_atomic_int(version_path, &oldVersion) == -1) { oldVersion = 0; } int version = oldVersion; if (version < 2) { SLOGD("Assuming that device has multi-user storage layout; upgrade no longer supported"); version = 2; } if (ensure_config_user_dirs(0) == -1) { SLOGE("Failed to setup misc for user 0"); goto fail; } if (version == 2) { SLOGD("Upgrading to /data/misc/user directories"); char misc_dir[PATH_MAX]; snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str()); char keychain_added_dir[PATH_MAX]; snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir); char keychain_removed_dir[PATH_MAX]; snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir); DIR *dir; struct dirent *dirent; dir = opendir("/data/user"); if (dir != NULL) { while ((dirent = readdir(dir))) { const char *name = dirent->d_name; // skip "." and ".." if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } uint32_t user_id = std::stoi(name); // /data/misc/user/<user_id> if (ensure_config_user_dirs(user_id) == -1) { goto fail; } char misc_added_dir[PATH_MAX]; snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name); char misc_removed_dir[PATH_MAX]; snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name); uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM); gid_t gid = uid; if (access(keychain_added_dir, F_OK) == 0) { if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) { SLOGE("Some files failed to copy"); } } if (access(keychain_removed_dir, F_OK) == 0) { if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) { SLOGE("Some files failed to copy"); } } } closedir(dir); if (access(keychain_added_dir, F_OK) == 0) { delete_dir_contents(keychain_added_dir, 1, 0); } if (access(keychain_removed_dir, F_OK) == 0) { delete_dir_contents(keychain_removed_dir, 1, 0); } } version = 3; } // Persist layout version if changed if (version != oldVersion) { if (fs_write_atomic_int(version_path, version) == -1) { SLOGE("Failed to save version to %s: %s", version_path, strerror(errno)); goto fail; } } // Success! res = 0; fail: return res; }
void get_derived_permission_lollipop(struct dentry *parent, struct dentry *dentry) { struct sdcardfslp_sb_info *sbi = SDCARDFSLP_SB(dentry->d_sb); struct sdcardfslp_inode_info *info = SDCARDFSLP_I(dentry->d_inode); struct sdcardfslp_inode_info *parent_info= SDCARDFSLP_I(parent->d_inode); appid_t appid; /* By default, each inode inherits from its parent. * the properties are maintained on its private fields * because the inode attributes will be modified with that of * its lower inode. * The derived state will be updated on the last * stage of each system call by fix_derived_permission(inode). */ inherit_derived_state(parent->d_inode, dentry->d_inode); //printk(KERN_INFO "sdcardfslp: derived: %s, %s, %d\n", parent->d_name.name, // dentry->d_name.name, parent_info->perm); if (sbi->options.derive == DERIVE_NONE) { return; } /* Derive custom permissions based on parent and current node */ switch (parent_info->perm) { case PERM_INHERIT: /* Already inherited above */ break; case PERM_LEGACY_PRE_ROOT: /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); break; case PERM_ROOT: /* Assume masked off by default. */ info->d_mode = 00770; if (!strcasecmp(dentry->d_name.name, "Android")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->d_mode = 00771; } else if (sbi->options.split_perms) { if (!strcasecmp(dentry->d_name.name, "DCIM") || !strcasecmp(dentry->d_name.name, "Pictures")) { info->d_gid = AID_SDCARD_PICS; } else if (!strcasecmp(dentry->d_name.name, "Alarms") || !strcasecmp(dentry->d_name.name, "Movies") || !strcasecmp(dentry->d_name.name, "Music") || !strcasecmp(dentry->d_name.name, "Notifications") || !strcasecmp(dentry->d_name.name, "Podcasts") || !strcasecmp(dentry->d_name.name, "Ringtones")) { info->d_gid = AID_SDCARD_AV; } } break; case PERM_ANDROID: if (!strcasecmp(dentry->d_name.name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; info->d_mode = 00771; } else if (!strcasecmp(dentry->d_name.name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; info->d_mode = 00771; // FIXME : this feature will be implemented later. /* Single OBB directory is always shared */ } else if (!strcasecmp(dentry->d_name.name, "media")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; info->d_mode = 00771; } else if (!strcasecmp(dentry->d_name.name, "user")) { /* User directories must only be accessible to system, protected * by sdcard_all. Zygote will bind mount the appropriate user- * specific path. */ info->perm = PERM_ANDROID_USER; info->d_gid = AID_SDCARD_ALL; info->d_mode = 00770; } break; /* same policy will be applied on PERM_ANDROID_DATA * and PERM_ANDROID_OBB */ case PERM_ANDROID_DATA: case PERM_ANDROID_OBB: case PERM_ANDROID_MEDIA: appid = get_appid_lollipop(sbi->pkgl_id, dentry->d_name.name); if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } info->d_mode = 00770; break; case PERM_ANDROID_USER: /* Root of a secondary user */ info->perm = PERM_ROOT; info->userid = simple_strtoul(dentry->d_name.name, NULL, 10); info->d_gid = AID_SDCARD_R; info->d_mode = 00771; break; } }