From: Daniel Rosenberg Date: Thu, 4 Feb 2016 05:08:21 +0000 (-0800) Subject: ANDROID: sdcardfs: Bring up to date with Android M permissions: X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=7fc95a91b4026be10453cb601f7225772cc78f24;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git ANDROID: sdcardfs: Bring up to date with Android M permissions: In M, the workings of sdcardfs were changed significantly. This brings sdcardfs into line with the changes. Change-Id: I10e91a84a884c838feef7aa26c0a2b21f02e052e --- diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig index d995f3eaae6d..ab25f88ebb37 100644 --- a/fs/sdcardfs/Kconfig +++ b/fs/sdcardfs/Kconfig @@ -1,5 +1,6 @@ config SDCARD_FS tristate "sdcard file system" + depends on CONFIGFS_FS default n help Sdcardfs is based on Wrapfs file system. diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 00c33a471dcc..128b3e56851f 100644 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -29,24 +29,23 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->perm = PERM_INHERIT; ci->userid = pi->userid; ci->d_uid = pi->d_uid; - ci->d_gid = pi->d_gid; - ci->d_mode = pi->d_mode; + ci->under_android = pi->under_android; } /* helper function for derived state */ void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, gid_t gid, mode_t mode) + userid_t userid, uid_t uid, bool under_android) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); info->perm = perm; info->userid = userid; info->d_uid = uid; - info->d_gid = gid; - info->d_mode = mode; + info->under_android = under_android; } -void get_derived_permission(struct dentry *parent, struct dentry *dentry) +/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ +void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry) { struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); @@ -63,86 +62,68 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) inherit_derived_state(parent->d_inode, dentry->d_inode); - //printk(KERN_INFO "sdcardfs: 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: + 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); + info->userid = simple_strtoul(newdentry->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")) { + if (!strcasecmp(newdentry->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; - } + info->under_android = true; } break; case PERM_ANDROID: - if (!strcasecmp(dentry->d_name.name, "data")) { + if (!strcasecmp(newdentry->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")) { + } else if (!strcasecmp(newdentry->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, "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; + } else if (!strcasecmp(newdentry->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: - appid = get_appid(sbi->pkgl_id, dentry->d_name.name); + case PERM_ANDROID_MEDIA: + appid = get_appid(sbi->pkgl_id, newdentry->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; } } +void get_derived_permission(struct dentry *parent, struct dentry *dentry) +{ + get_derived_permission_new(parent, dentry, dentry); +} + +void get_derive_permissions_recursive(struct dentry *parent) { + struct dentry *dentry; + list_for_each_entry(dentry, &parent->d_subdirs, d_child) { + if (dentry && dentry->d_inode) { + mutex_lock(&dentry->d_inode->i_mutex); + get_derived_permission(parent, dentry); + fix_derived_permission(dentry->d_inode); + get_derive_permissions_recursive(dentry); + mutex_unlock(&dentry->d_inode->i_mutex); + } + } +} + /* main function for updating derived permission */ -inline void update_derived_permission(struct dentry *dentry) +inline void update_derived_permission_lock(struct dentry *dentry) { struct dentry *parent; @@ -154,6 +135,7 @@ inline void update_derived_permission(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ + mutex_lock(&dentry->d_inode->i_mutex); if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { @@ -164,6 +146,7 @@ inline void update_derived_permission(struct dentry *dentry) } } fix_derived_permission(dentry->d_inode); + mutex_unlock(&dentry->d_inode->i_mutex); } int need_graft_path(struct dentry *dentry) @@ -177,7 +160,7 @@ int need_graft_path(struct dentry *dentry) !strcasecmp(dentry->d_name.name, "obb")) { /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ - if(!(sbi->options.derive == DERIVE_UNIFIED + if(!(sbi->options.multiuser == false && parent_info->userid == 0)) { ret = 1; } @@ -207,8 +190,7 @@ int is_obbpath_invalid(struct dentry *dent) path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); if(!path_buf) { ret = 1; - printk(KERN_ERR "sdcardfs: " - "fail to allocate path_buf in %s.\n", __func__); + printk(KERN_ERR "sdcardfs: fail to allocate path_buf in %s.\n", __func__); } else { obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX); if (d_unhashed(di->lower_path.dentry) || @@ -234,21 +216,16 @@ int is_base_obbpath(struct dentry *dentry) struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); spin_lock(&SDCARDFS_D(dentry)->lock); - /* DERIVED_LEGACY */ - if(parent_info->perm == PERM_LEGACY_PRE_ROOT && - !strcasecmp(dentry->d_name.name, "obb")) { - ret = 1; - } - /* DERIVED_UNIFIED :/Android/obb is the base obbpath */ - else if (parent_info->perm == PERM_ANDROID && - !strcasecmp(dentry->d_name.name, "obb")) { - if((sbi->options.derive == DERIVE_UNIFIED - && parent_info->userid == 0)) { + if (sbi->options.multiuser) { + if(parent_info->perm == PERM_PRE_ROOT && + !strcasecmp(dentry->d_name.name, "obb")) { ret = 1; } + } else if (parent_info->perm == PERM_ANDROID && + !strcasecmp(dentry->d_name.name, "obb")) { + ret = 1; } spin_unlock(&SDCARDFS_D(dentry)->lock); - dput(parent); return ret; } @@ -272,8 +249,7 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) if(!err) { /* the obbpath base has been found */ - printk(KERN_INFO "sdcardfs: " - "the sbi->obbpath is found\n"); + printk(KERN_INFO "sdcardfs: the sbi->obbpath is found\n"); pathcpy(lower_path, &obbpath); } else { /* if the sbi->obbpath is not available, we can optionally @@ -281,8 +257,7 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) * but, the current implementation just returns an error * because the sdcard daemon also regards this case as * a lookup fail. */ - printk(KERN_INFO "sdcardfs: " - "the sbi->obbpath is not available\n"); + printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n"); } return err; } diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index f9c5eaafc619..c249fa982d3c 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -209,7 +209,6 @@ static int sdcardfs_open(struct inode *inode, struct file *file) struct dentry *parent = dget_parent(dentry); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { @@ -217,11 +216,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) goto out_err; } - has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, - sbi->options.derive, - open_flags_to_access_mode(file->f_flags), has_rw)) { + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -257,8 +252,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) if (err) kfree(SDCARDFS_F(file)); else { - fsstack_copy_attr_all(inode, sdcardfs_lower_inode(inode)); - fix_derived_permission(inode); + sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode)); } out_revert_cred: diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 75c622bac2f5..2528da0d3ae1 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -55,11 +55,9 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -80,7 +78,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, if (err) goto out; - err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, SDCARDFS_I(dir)->userid); if (err) goto out; fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); @@ -143,11 +141,9 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) struct inode *lower_dir_inode = sdcardfs_lower_inode(dir); struct dentry *lower_dir_dentry; struct path lower_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -255,8 +251,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode int fullpath_namelen; int touch_err = 0; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -293,19 +288,19 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode if(err) { /* if the sbi->obbpath is not available, the lower_path won't be * changed by setup_obb_dentry() but the lower path is saved to - * its orig_path. this dentry will be revalidated later. + * its orig_path. this dentry will be revalidated later. * but now, the lower_path should be NULL */ sdcardfs_put_reset_lower_path(dentry); /* the newly created lower path which saved to its orig_path or * the lower_path is the base obbpath. - * therefore, an additional path_get is required */ + * therefore, an additional path_get is required */ path_get(&lower_path); } else make_nomedia_in_obb = 1; } - err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid); if (err) goto out; @@ -314,7 +309,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* update number of links on parent directory */ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); - if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb")) + if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; @@ -371,12 +366,9 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) struct dentry *lower_dir_dentry; int err; struct path lower_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; - //char *path_s = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -461,14 +453,10 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct dentry *trap = NULL; struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(old_dentry->d_sb); const struct cred *saved_cred = NULL; - int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); - if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name, - sbi->options.derive, 1, has_rw) || - !check_caller_access_to_name(new_dir, new_dentry->d_name.name, - sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name) || + !check_caller_access_to_name(new_dir, new_dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " new_dentry: %s, task:%s\n", __func__, new_dentry->d_name.name, current->comm); @@ -505,26 +493,31 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; /* Copy attrs from lower dir, but i_uid/i_gid */ - fsstack_copy_attr_all(new_dir, d_inode(lower_new_dir_dentry)); + sdcardfs_copy_and_fix_attrs(new_dir, d_inode(lower_new_dir_dentry)); fsstack_copy_inode_size(new_dir, d_inode(lower_new_dir_dentry)); - fix_derived_permission(new_dir); + if (new_dir != old_dir) { - fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry)); + sdcardfs_copy_and_fix_attrs(old_dir, d_inode(lower_old_dir_dentry)); fsstack_copy_inode_size(old_dir, d_inode(lower_old_dir_dentry)); - fix_derived_permission(old_dir); + /* update the derived permission of the old_dentry * with its new parent */ new_parent = dget_parent(new_dentry); if(new_parent) { if(d_inode(old_dentry)) { - get_derived_permission(new_parent, old_dentry); - fix_derived_permission(d_inode(old_dentry)); + update_derived_permission_lock(old_dentry); } dput(new_parent); } } - + /* At this point, not all dentry information has been moved, so + * we pass along new_dentry for the name.*/ + mutex_lock(&d_inode(old_dentry)->i_mutex); + get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); + fix_derived_permission(d_inode(old_dentry)); + get_derive_permissions_recursive(old_dentry); + mutex_unlock(&d_inode(old_dentry)->i_mutex); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -639,9 +632,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) struct inode *lower_inode; struct path lower_path; struct iattr lower_ia; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct dentry *parent; - int has_rw; inode = d_inode(dentry); @@ -655,10 +646,8 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) /* no vfs_XXX operations required, cred overriding will be skipped. wj*/ if (!err) { /* check the Android group ID */ - has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); parent = dget_parent(dentry); - if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name, - sbi->options.derive, 1, has_rw)) { + if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -723,10 +712,8 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) if (err) goto out; - /* get attributes from the lower inode */ - fsstack_copy_attr_all(inode, lower_inode); - /* update derived permission of the upper inode */ - fix_derived_permission(inode); + /* get attributes from the lower inode and update derived permissions */ + sdcardfs_copy_and_fix_attrs(inode, lower_inode); /* * Not running fsstack_copy_inode_size(inode, lower_inode), because @@ -748,11 +735,9 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct inode *lower_inode; struct path lower_path; struct dentry *parent; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); parent = dget_parent(dentry); - if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name, - sbi->options.derive, 0, 0)) { + if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -767,13 +752,10 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); - fsstack_copy_attr_all(inode, lower_inode); + + sdcardfs_copy_and_fix_attrs(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); - /* if the dentry has been moved from other location - * so, on this stage, its derived permission must be - * rechecked from its private field. - */ - fix_derived_permission(inode); + generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a4b94df99f32..f80abcb6b467 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -64,10 +64,17 @@ int new_dentry_private_data(struct dentry *dentry) return 0; } -static int sdcardfs_inode_test(struct inode *inode, void *candidate_lower_inode) +struct inode_data { + struct inode *lower_inode; + userid_t id; +}; + +static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void *candidate_lower_inode*/) { struct inode *current_lower_inode = sdcardfs_lower_inode(inode); - if (current_lower_inode == (struct inode *)candidate_lower_inode) + userid_t current_userid = SDCARDFS_I(inode)->userid; + if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode && + current_userid == ((struct inode_data *)candidate_data)->id) return 1; /* found a match */ else return 0; /* no match */ @@ -79,12 +86,15 @@ static int sdcardfs_inode_set(struct inode *inode, void *lower_inode) return 0; } -struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) +struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, userid_t id) { struct sdcardfs_inode_info *info; + struct inode_data data; struct inode *inode; /* the new inode to return */ int err; + data.id = id; + data.lower_inode = lower_inode; inode = iget5_locked(sb, /* our superblock */ /* * hashval: we use inode number, but we can @@ -94,7 +104,7 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) lower_inode->i_ino, /* hashval */ sdcardfs_inode_test, /* inode comparison function */ sdcardfs_inode_set, /* inode init function */ - lower_inode); /* data passed to test+set fxns */ + &data); /* data passed to test+set fxns */ if (!inode) { err = -EACCES; iput(lower_inode); @@ -146,11 +156,9 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) lower_inode->i_rdev); /* all well, copy inode attributes */ - fsstack_copy_attr_all(inode, lower_inode); + sdcardfs_copy_and_fix_attrs(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); - fix_derived_permission(inode); - unlock_new_inode(inode); return inode; } @@ -164,7 +172,7 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode) * @lower_path: the lower path (caller does path_get/put) */ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, - struct path *lower_path) + struct path *lower_path, userid_t id) { int err = 0; struct inode *inode; @@ -186,14 +194,14 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, */ /* inherit lower inode number for sdcardfs's inode */ - inode = sdcardfs_iget(sb, lower_inode); + inode = sdcardfs_iget(sb, lower_inode, id); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out; } d_add(dentry, inode); - update_derived_permission(dentry); + update_derived_permission_lock(dentry); out: return err; } @@ -205,7 +213,7 @@ out: * Fills in lower_parent_path with on success. */ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, - unsigned int flags, struct path *lower_parent_path) + unsigned int flags, struct path *lower_parent_path, userid_t id) { int err = 0; struct vfsmount *lower_dir_mnt; @@ -266,7 +274,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, } sdcardfs_set_lower_path(dentry, &lower_path); - err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path); + err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id); if (err) /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); goto out; @@ -328,13 +336,11 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, struct dentry *ret = NULL, *parent; struct path lower_parent_path; int err = 0; - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, - sbi->options.derive, 0, 0)) { + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { ret = ERR_PTR(-EACCES); printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", @@ -354,7 +360,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, goto out; } - ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path); + ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path, SDCARDFS_I(dir)->userid); if (IS_ERR(ret)) { goto out; @@ -365,8 +371,10 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); /* get drived permission */ + mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); + mutex_unlock(&dentry->d_inode->i_mutex); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 9d04ae8ceb46..80aa355d801e 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -24,25 +24,27 @@ #include enum { - Opt_uid, + Opt_fsuid, + Opt_fsgid, Opt_gid, - Opt_wgid, Opt_debug, - Opt_split, - Opt_derive, Opt_lower_fs, + Opt_mask, + Opt_multiuser, // May need? + Opt_userid, Opt_reserved_mb, Opt_err, }; static const match_table_t sdcardfs_tokens = { - {Opt_uid, "uid=%u"}, + {Opt_fsuid, "fsuid=%u"}, + {Opt_fsgid, "fsgid=%u"}, {Opt_gid, "gid=%u"}, - {Opt_wgid, "wgid=%u"}, {Opt_debug, "debug"}, - {Opt_split, "split"}, - {Opt_derive, "derive=%s"}, {Opt_lower_fs, "lower_fs=%s"}, + {Opt_mask, "mask=%u"}, + {Opt_userid, "userid=%d"}, + {Opt_multiuser, "multiuser"}, {Opt_reserved_mb, "reserved_mb=%u"}, {Opt_err, NULL} }; @@ -58,12 +60,10 @@ static int parse_options(struct super_block *sb, char *options, int silent, /* by default, we use AID_MEDIA_RW as uid, gid */ opts->fs_low_uid = AID_MEDIA_RW; opts->fs_low_gid = AID_MEDIA_RW; - /* by default, we use AID_SDCARD_RW as write_gid */ - opts->write_gid = AID_SDCARD_RW; - /* default permission policy - * (DERIVE_NONE | DERIVE_LEGACY | DERIVE_UNIFIED) */ - opts->derive = DERIVE_NONE; - opts->split_perms = 0; + opts->mask = 0; + opts->multiuser = false; + opts->fs_user_id = 0; + opts->gid = 0; /* by default, we use LOWER_FS_EXT4 as lower fs type */ opts->lower_fs = LOWER_FS_EXT4; /* by default, 0MB is reserved */ @@ -85,37 +85,33 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_debug: *debug = 1; break; - case Opt_uid: + case Opt_fsuid: if (match_int(&args[0], &option)) return 0; opts->fs_low_uid = option; break; - case Opt_gid: + case Opt_fsgid: if (match_int(&args[0], &option)) return 0; opts->fs_low_gid = option; break; - case Opt_wgid: + case Opt_gid: if (match_int(&args[0], &option)) return 0; - opts->write_gid = option; + opts->gid = option; break; - case Opt_split: - opts->split_perms=1; + case Opt_userid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_user_id = option; break; - case Opt_derive: - string_option = match_strdup(&args[0]); - if (!strcmp("none", string_option)) { - opts->derive = DERIVE_NONE; - } else if (!strcmp("legacy", string_option)) { - opts->derive = DERIVE_LEGACY; - } else if (!strcmp("unified", string_option)) { - opts->derive = DERIVE_UNIFIED; - } else { - kfree(string_option); - goto invalid_option; - } - kfree(string_option); + case Opt_mask: + if (match_int(&args[0], &option)) + return 0; + opts->mask = option; + break; + case Opt_multiuser: + opts->multiuser = true; break; case Opt_lower_fs: string_option = match_strdup(&args[0]); @@ -184,6 +180,11 @@ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) } #endif +DEFINE_MUTEX(sdcardfs_super_list_lock); +LIST_HEAD(sdcardfs_super_list); +EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock); +EXPORT_SYMBOL_GPL(sdcardfs_super_list); + /* * 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. @@ -196,7 +197,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; - void *pkgl_id; struct inode *inode; printk(KERN_INFO "sdcardfs version 2.0\n"); @@ -215,8 +215,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, 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); + printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name); goto out; } @@ -229,7 +228,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, } sb_info = sb->s_fs_info; - /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { @@ -237,14 +235,6 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, goto out_freesbi; } - if (sb_info->options.derive != DERIVE_NONE) { - pkgl_id = packagelist_create(sb_info->options.write_gid); - 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); @@ -263,7 +253,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb->s_op = &sdcardfs_sops; /* get a new inode and allocate our root dentry */ - inode = sdcardfs_iget(sb, lower_path.dentry->d_inode); + inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_sput; @@ -292,41 +282,22 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, d_rehash(sb->s_root); /* setup permission policy */ - switch(sb_info->options.derive) { - case DERIVE_NONE: - setup_derived_state(sb->s_root->d_inode, - PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775); - sb_info->obbpath_s = NULL; - break; - case DERIVE_LEGACY: - /* Legacy behavior used to support internal multiuser layout which - * places user_id at the top directory level, with the actual roots - * just below that. Shared OBB path is also at top level. */ - setup_derived_state(sb->s_root->d_inode, - PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); - /* initialize the obbpath string and lookup the path - * sb_info->obb_path will be deactivated by path_put - * on sdcardfs_put_super */ - sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); - snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); - err = prepare_dir(sb_info->obbpath_s, + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + mutex_lock(&sdcardfs_super_list_lock); + if(sb_info->options.multiuser) { + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); + /*err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, - sb_info->options.fs_low_gid, 00755); - if(err) - printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n", - __func__,__LINE__, sb_info->obbpath_s); - break; - case DERIVE_UNIFIED: - /* Unified multiuser layout which places secondary user_id under - * /Android/user and shared OBB path under /Android/obb. */ - setup_derived_state(sb->s_root->d_inode, - PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); - - sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); - snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); - break; + sb_info->options.fs_low_gid, 00755);*/ + } else { + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); + sb_info->sb = sb; + list_add(&sb_info->list, &sdcardfs_super_list); + mutex_unlock(&sdcardfs_super_list_lock); if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", @@ -341,7 +312,6 @@ out_iput: 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; @@ -386,11 +356,22 @@ struct dentry *sdcardfs_mount(struct file_system_type *fs_type, int flags, raw_data, sdcardfs_read_super); } +void sdcardfs_kill_sb(struct super_block *sb) { + struct sdcardfs_sb_info *sbi; + if (sb->s_magic == SDCARDFS_SUPER_MAGIC) { + sbi = SDCARDFS_SB(sb); + mutex_lock(&sdcardfs_super_list_lock); + list_del(&sbi->list); + mutex_unlock(&sdcardfs_super_list_lock); + } + generic_shutdown_super(sb); +} + static struct file_system_type sdcardfs_fs_type = { .owner = THIS_MODULE, .name = SDCARDFS_NAME, .mount = sdcardfs_mount, - .kill_sb = generic_shutdown_super, + .kill_sb = sdcardfs_kill_sb, .fs_flags = 0, }; diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index f11591da141d..ba3478d94107 100644 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -19,13 +19,16 @@ */ #include "sdcardfs.h" -#include "strtok.h" #include -#include -#include -#include #include + +#include +#include +#include + +#include + #define STRING_BUF_SIZE (512) struct hashtable_entry { @@ -34,25 +37,20 @@ struct hashtable_entry { unsigned int value; }; +struct sb_list { + struct super_block *sb; + struct list_head list; +}; + struct packagelist_data { DECLARE_HASHTABLE(package_to_appid,8); - DECLARE_HASHTABLE(appid_with_rw,7); struct mutex hashtable_lock; - struct task_struct *thread_id; - gid_t write_gid; - char *strtok_last; - char read_buf[STRING_BUF_SIZE]; - char event_buf[STRING_BUF_SIZE]; - char app_name_buf[STRING_BUF_SIZE]; - char gids_buf[STRING_BUF_SIZE]; + }; -static struct kmem_cache *hashtable_entry_cachep; +static struct packagelist_data *pkgl_data_all; -/* Path to system-provided mapping of package name to appIds */ -static const char* const kpackageslist_file = "/data/system/packages.list"; -/* Supplementary groups to execute with */ -static const gid_t kgroups[1] = { AID_PACKAGE_INFO }; +static struct kmem_cache *hashtable_entry_cachep; static unsigned int str_hash(const char *key) { int i; @@ -66,62 +64,29 @@ static unsigned int str_hash(const char *key) { return h; } -static int contain_appid_key(struct packagelist_data *pkgl_dat, unsigned int appid) { - struct hashtable_entry *hash_cur; - - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, appid) - if ((void *)(uintptr_t)appid == hash_cur->key) - return 1; - - return 0; -} - -/* Return if the calling UID holds sdcard_rw. */ -int get_caller_has_rw_locked(void *pkgl_id, derive_t derive) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; - appid_t appid; - int ret; - - /* No additional permissions enforcement */ - if (derive == DERIVE_NONE) { - return 1; - } - - appid = multiuser_get_app_id(from_kuid(&init_user_ns, current_fsuid())); - mutex_lock(&pkgl_dat->hashtable_lock); - ret = contain_appid_key(pkgl_dat, appid); - mutex_unlock(&pkgl_dat->hashtable_lock); - return ret; -} - appid_t get_appid(void *pkgl_id, const char *app_name) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; + struct packagelist_data *pkgl_dat = pkgl_data_all; struct hashtable_entry *hash_cur; unsigned int hash = str_hash(app_name); appid_t ret_id; - //printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash); mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { - //printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key); if (!strcasecmp(app_name, hash_cur->key)) { ret_id = (appid_t)hash_cur->value; mutex_unlock(&pkgl_dat->hashtable_lock); - //printk(KERN_INFO "=> app_id: %d\n", (int)ret_id); return ret_id; } } mutex_unlock(&pkgl_dat->hashtable_lock); - //printk(KERN_INFO "=> app_id: %d\n", 0); return 0; } /* Kernel has already enforced everything we returned through * derive_permissions_locked(), so this is used to lock down access * even further, such as enforcing that apps hold sdcard_rw. */ -int check_caller_access_to_name(struct inode *parent_node, const char* name, - derive_t derive, int w_ok, int has_rw) { +int check_caller_access_to_name(struct inode *parent_node, const char* name) { /* Always block security-sensitive files at root */ if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { @@ -132,28 +97,12 @@ int check_caller_access_to_name(struct inode *parent_node, const char* name, } } - /* No additional permissions enforcement */ - if (derive == DERIVE_NONE) { - return 1; - } - /* Root always has access; access for any other UIDs should always * be controlled through packages.list. */ if (from_kuid(&init_user_ns, current_fsuid()) == 0) { return 1; } - /* If asking to write, verify that caller either owns the - * parent or holds sdcard_rw. */ - if (w_ok) { - if (parent_node && - (from_kuid(&init_user_ns, current_fsuid()) == - SDCARDFS_I(parent_node)->d_uid)) { - return 1; - } - return has_rw; - } - /* No extra permissions to enforce */ return 1; } @@ -171,14 +120,13 @@ int open_flags_to_access_mode(int open_flags) { } } -static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, +static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, unsigned int value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; unsigned int hash = str_hash(key); - //printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { hash_cur->value = value; @@ -194,245 +142,275 @@ static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, return 0; } -static void remove_str_to_int(struct hashtable_entry *h_entry) { - //printk(KERN_INFO "sdcardfs: %s: %s: %d\n", __func__, (char *)h_entry->key, h_entry->value); - kfree(h_entry->key); - kmem_cache_free(hashtable_entry_cachep, h_entry); +static void fixup_perms(struct super_block *sb) { + if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { + mutex_lock(&sb->s_root->d_inode->i_mutex); + get_derive_permissions_recursive(sb->s_root); + mutex_unlock(&sb->s_root->d_inode->i_mutex); + } } -static int insert_int_to_null(struct packagelist_data *pkgl_dat, unsigned int key, - unsigned int value) -{ - struct hashtable_entry *hash_cur; - struct hashtable_entry *new_entry; +static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, + unsigned int value) { + int ret; + struct sdcardfs_sb_info *sbinfo; + mutex_lock(&sdcardfs_super_list_lock); + mutex_lock(&pkgl_dat->hashtable_lock); + ret = insert_str_to_int_lock(pkgl_dat, key, value); + mutex_unlock(&pkgl_dat->hashtable_lock); - //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value); - hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, key) { - if ((void *)(uintptr_t)key == hash_cur->key) { - hash_cur->value = value; - return 0; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo) { + fixup_perms(sbinfo->sb); } } - new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); - if (!new_entry) - return -ENOMEM; - new_entry->key = (void *)(uintptr_t)key; - new_entry->value = value; - hash_add(pkgl_dat->appid_with_rw, &new_entry->hlist, key); - return 0; + mutex_unlock(&sdcardfs_super_list_lock); + return ret; } -static void remove_int_to_null(struct hashtable_entry *h_entry) { - //printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)h_entry->key, h_entry->value); +static void remove_str_to_int_lock(struct hashtable_entry *h_entry) { + kfree(h_entry->key); + hash_del(&h_entry->hlist); kmem_cache_free(hashtable_entry_cachep, h_entry); } +static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key) +{ + struct sdcardfs_sb_info *sbinfo; + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(key); + mutex_lock(&sdcardfs_super_list_lock); + mutex_lock(&pkgl_dat->hashtable_lock); + hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key)) { + remove_str_to_int_lock(hash_cur); + break; + } + } + mutex_unlock(&pkgl_dat->hashtable_lock); + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo) { + fixup_perms(sbinfo->sb); + } + } + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) { struct hashtable_entry *hash_cur; struct hlist_node *h_t; int i; - + mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) - remove_str_to_int(hash_cur); - hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist) - remove_int_to_null(hash_cur); - + remove_str_to_int_lock(hash_cur); + mutex_unlock(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); - hash_init(pkgl_dat->appid_with_rw); } -static int read_package_list(struct packagelist_data *pkgl_dat) { - int ret; - int fd; - int read_amount; +static struct packagelist_data * packagelist_create(void) +{ + struct packagelist_data *pkgl_dat; - printk(KERN_INFO "sdcardfs: read_package_list\n"); + pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); + if (!pkgl_dat) { + printk(KERN_ERR "sdcardfs: Failed to create hash\n"); + return ERR_PTR(-ENOMEM); + } - mutex_lock(&pkgl_dat->hashtable_lock); + mutex_init(&pkgl_dat->hashtable_lock); + hash_init(pkgl_dat->package_to_appid); + + return pkgl_dat; +} +static void packagelist_destroy(struct packagelist_data *pkgl_dat) +{ remove_all_hashentrys(pkgl_dat); + printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); + kfree(pkgl_dat); +} - fd = sys_open(kpackageslist_file, O_RDONLY, 0); - if (fd < 0) { - printk(KERN_ERR "sdcardfs: failed to open package list\n"); - mutex_unlock(&pkgl_dat->hashtable_lock); - return fd; - } +struct package_appid { + struct config_item item; + int add_pid; +}; - while ((read_amount = sys_read(fd, pkgl_dat->read_buf, - sizeof(pkgl_dat->read_buf))) > 0) { - unsigned int appid; - char *token; - int one_line_len = 0; - int additional_read; - unsigned long ret_gid; - - while (one_line_len < read_amount) { - if (pkgl_dat->read_buf[one_line_len] == '\n') { - one_line_len++; - break; - } - one_line_len++; - } - additional_read = read_amount - one_line_len; - if (additional_read > 0) - sys_lseek(fd, -additional_read, SEEK_CUR); - - if (sscanf(pkgl_dat->read_buf, "%s %u %*d %*s %*s %s", - pkgl_dat->app_name_buf, &appid, - pkgl_dat->gids_buf) == 3) { - ret = insert_str_to_int(pkgl_dat, pkgl_dat->app_name_buf, appid); - if (ret) { - sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); - return ret; - } - - token = strtok_r(pkgl_dat->gids_buf, ",", &pkgl_dat->strtok_last); - while (token != NULL) { - if (!kstrtoul(token, 10, &ret_gid) && - (ret_gid == pkgl_dat->write_gid)) { - ret = insert_int_to_null(pkgl_dat, appid, 1); - if (ret) { - sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); - return ret; - } - break; - } - token = strtok_r(NULL, ",", &pkgl_dat->strtok_last); - } - } - } +static inline struct package_appid *to_package_appid(struct config_item *item) +{ + return item ? container_of(item, struct package_appid, item) : NULL; +} - sys_close(fd); - mutex_unlock(&pkgl_dat->hashtable_lock); - return 0; +static ssize_t package_appid_attr_show(struct config_item *item, + char *page) +{ + ssize_t count; + count = sprintf(page, "%d\n", get_appid(pkgl_data_all, item->ci_name)); + return count; } -static int packagelist_reader(void *thread_data) +static ssize_t package_appid_attr_store(struct config_item *item, + const char *page, size_t count) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)thread_data; - struct inotify_event *event; - bool active = false; - int event_pos; - int event_size; - int res = 0; - int nfd; - - allow_signal(SIGINT); - - nfd = sys_inotify_init(); - if (nfd < 0) { - printk(KERN_ERR "sdcardfs: inotify_init failed: %d\n", nfd); - return nfd; - } + struct package_appid *package_appid = to_package_appid(item); + unsigned long tmp; + char *p = (char *) page; + int ret; - while (!kthread_should_stop()) { - if (signal_pending(current)) { - ssleep(1); - continue; - } + tmp = simple_strtoul(p, &p, 10); + if (!p || (*p && (*p != '\n'))) + return -EINVAL; - if (!active) { - res = sys_inotify_add_watch(nfd, kpackageslist_file, IN_DELETE_SELF); - if (res < 0) { - if (res == -ENOENT || res == -EACCES) { - /* Framework may not have created yet, sleep and retry */ - printk(KERN_ERR "sdcardfs: missing packages.list; retrying\n"); - ssleep(2); - printk(KERN_ERR "sdcardfs: missing packages.list_end; retrying\n"); - continue; - } else { - printk(KERN_ERR "sdcardfs: inotify_add_watch failed: %d\n", res); - goto interruptable_sleep; - } - } - /* Watch above will tell us about any future changes, so - * read the current state. */ - res = read_package_list(pkgl_dat); - if (res) { - printk(KERN_ERR "sdcardfs: read_package_list failed: %d\n", res); - goto interruptable_sleep; - } - active = true; - } + if (tmp > INT_MAX) + return -ERANGE; + ret = insert_str_to_int(pkgl_data_all, item->ci_name, (unsigned int)tmp); + package_appid->add_pid = tmp; + if (ret) + return ret; - event_pos = 0; - res = sys_read(nfd, pkgl_dat->event_buf, sizeof(pkgl_dat->event_buf)); - if (res < (int) sizeof(*event)) { - if (res == -EINTR) - continue; - printk(KERN_ERR "sdcardfs: failed to read inotify event: %d\n", res); - goto interruptable_sleep; - } + return count; +} - while (res >= (int) sizeof(*event)) { - event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos); +static struct configfs_attribute package_appid_attr_add_pid = { + .ca_owner = THIS_MODULE, + .ca_name = "appid", + .ca_mode = S_IRUGO | S_IWUGO, + .show = package_appid_attr_show, + .store = package_appid_attr_store, +}; - printk(KERN_INFO "sdcardfs: inotify event: %08x\n", event->mask); - if ((event->mask & IN_IGNORED) == IN_IGNORED) { - /* Previously watched file was deleted, probably due to move - * that swapped in new data; re-arm the watch and read. */ - active = false; - } +static struct configfs_attribute *package_appid_attrs[] = { + &package_appid_attr_add_pid, + NULL, +}; - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } - continue; +static void package_appid_release(struct config_item *item) +{ + printk(KERN_INFO "sdcardfs: removing %s\n", item->ci_dentry->d_name.name); + /* item->ci_name is freed already, so we rely on the dentry */ + remove_str_to_int(pkgl_data_all, item->ci_dentry->d_name.name); + kfree(to_package_appid(item)); +} -interruptable_sleep: - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - flush_signals(current); - sys_close(nfd); - return res; +static struct configfs_item_operations package_appid_item_ops = { + .release = package_appid_release, +}; + +static struct config_item_type package_appid_type = { + .ct_item_ops = &package_appid_item_ops, + .ct_attrs = package_appid_attrs, + .ct_owner = THIS_MODULE, +}; + + +struct sdcardfs_packages { + struct config_group group; +}; + +static inline struct sdcardfs_packages *to_sdcardfs_packages(struct config_item *item) +{ + return item ? container_of(to_config_group(item), struct sdcardfs_packages, group) : NULL; } -void * packagelist_create(gid_t write_gid) +static struct config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name) { - struct packagelist_data *pkgl_dat; - struct task_struct *packagelist_thread; + struct package_appid *package_appid; - pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); - if (!pkgl_dat) { - printk(KERN_ERR "sdcardfs: creating kthread failed\n"); + package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL); + if (!package_appid) return ERR_PTR(-ENOMEM); - } - mutex_init(&pkgl_dat->hashtable_lock); - hash_init(pkgl_dat->package_to_appid); - hash_init(pkgl_dat->appid_with_rw); - pkgl_dat->write_gid = write_gid; + config_item_init_type_name(&package_appid->item, name, + &package_appid_type); + + package_appid->add_pid = 0; - packagelist_thread = kthread_run(packagelist_reader, (void *)pkgl_dat, "pkgld"); - if (IS_ERR(packagelist_thread)) { - printk(KERN_ERR "sdcardfs: creating kthread failed\n"); - kfree(pkgl_dat); - return packagelist_thread; - } - pkgl_dat->thread_id = packagelist_thread; + return &package_appid->item; +} - printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n", - (int)pkgl_dat->thread_id->pid); +static ssize_t packages_attr_show(struct config_item *item, + char *page) +{ + struct hashtable_entry *hash_cur; + struct hlist_node *h_t; + int i; + int count = 0; + mutex_lock(&pkgl_data_all->hashtable_lock); + hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) + count += snprintf(page + count, PAGE_SIZE - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); + mutex_unlock(&pkgl_data_all->hashtable_lock); - return (void *)pkgl_dat; + + return count; } -void packagelist_destroy(void *pkgl_id) +static struct configfs_attribute sdcardfs_packages_attr_description = { + .ca_owner = THIS_MODULE, + .ca_name = "packages_gid.list", + .ca_mode = S_IRUGO, + .show = packages_attr_show, +}; + +static struct configfs_attribute *sdcardfs_packages_attrs[] = { + &sdcardfs_packages_attr_description, + NULL, +}; + +static void sdcardfs_packages_release(struct config_item *item) { - struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id; - pid_t pkgl_pid = pkgl_dat->thread_id->pid; - force_sig_info(SIGINT, SEND_SIG_PRIV, pkgl_dat->thread_id); - kthread_stop(pkgl_dat->thread_id); - remove_all_hashentrys(pkgl_dat); - printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld/%d\n", (int)pkgl_pid); - kfree(pkgl_dat); + printk(KERN_INFO "sdcardfs: destroyed something?\n"); + kfree(to_sdcardfs_packages(item)); +} + +static struct configfs_item_operations sdcardfs_packages_item_ops = { + .release = sdcardfs_packages_release, +}; + +/* + * Note that, since no extra work is required on ->drop_item(), + * no ->drop_item() is provided. + */ +static struct configfs_group_operations sdcardfs_packages_group_ops = { + .make_item = sdcardfs_packages_make_item, +}; + +static struct config_item_type sdcardfs_packages_type = { + .ct_item_ops = &sdcardfs_packages_item_ops, + .ct_group_ops = &sdcardfs_packages_group_ops, + .ct_attrs = sdcardfs_packages_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem sdcardfs_packages_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "sdcardfs", + .ci_type = &sdcardfs_packages_type, + }, + }, +}; + +static int __init configfs_sdcardfs_init(void) +{ + int ret; + struct configfs_subsystem *subsys = &sdcardfs_packages_subsys; + + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + ret = configfs_register_subsystem(subsys); + if (ret) { + printk(KERN_ERR "Error %d while registering subsystem %s\n", + ret, + subsys->su_group.cg_item.ci_namebuf); + } + return ret; +} + +static void __exit configfs_sdcardfs_exit(void) +{ + configfs_unregister_subsystem(&sdcardfs_packages_subsys); } int packagelist_init(void) @@ -445,13 +423,15 @@ int packagelist_init(void) return -ENOMEM; } + pkgl_data_all = packagelist_create(); + configfs_sdcardfs_init(); return 0; } void packagelist_exit(void) { + configfs_sdcardfs_exit(); + packagelist_destroy(pkgl_data_all); if (hashtable_entry_cachep) kmem_cache_destroy(hashtable_entry_cachep); } - - diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 51f6c7912584..1b85f4e70324 100644 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "multiuser.h" /* the file system name */ @@ -70,10 +71,11 @@ #define fix_derived_permission(x) \ do { \ (x)->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(x)->d_uid); \ - (x)->i_gid = make_kgid(&init_user_ns, SDCARDFS_I(x)->d_gid); \ - (x)->i_mode = ((x)->i_mode & S_IFMT) | SDCARDFS_I(x)->d_mode;\ + (x)->i_gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(x))); \ + (x)->i_mode = ((x)->i_mode & S_IFMT) | get_mode(SDCARDFS_I(x));\ } while (0) + /* OVERRIDE_CRED() and REVERT_CRED() * OVERRID_CRED() * backup original task->cred @@ -99,35 +101,28 @@ (int)current->cred->fsuid, \ (int)current->cred->fsgid); -/* Android 4.4 support */ +/* Android 5.0 support */ /* Permission mode for a specific node. Controls how file permissions * are derived for children nodes. */ typedef enum { - /* Nothing special; this node should just inherit from its parent. */ - PERM_INHERIT, - /* This node is one level above a normal root; used for legacy layouts - * which use the first level to represent user_id. */ - PERM_LEGACY_PRE_ROOT, - /* This node is "/" */ - PERM_ROOT, - /* This node is "/Android" */ - PERM_ANDROID, - /* This node is "/Android/data" */ - PERM_ANDROID_DATA, - /* This node is "/Android/obb" */ - PERM_ANDROID_OBB, - /* This node is "/Android/user" */ - PERM_ANDROID_USER, + /* Nothing special; this node should just inherit from its parent. */ + PERM_INHERIT, + /* This node is one level above a normal root; used for legacy layouts + * which use the first level to represent user_id. */ + PERM_PRE_ROOT, + /* This node is "/" */ + PERM_ROOT, + /* This node is "/Android" */ + PERM_ANDROID, + /* This node is "/Android/data" */ + PERM_ANDROID_DATA, + /* This node is "/Android/obb" */ + PERM_ANDROID_OBB, + /* This node is "/Android/media" */ + PERM_ANDROID_MEDIA, } perm_t; -/* Permissions structure to derive */ -typedef enum { - DERIVE_NONE, - DERIVE_LEGACY, - DERIVE_UNIFIED, -} derive_t; - typedef enum { LOWER_FS_EXT4, LOWER_FS_FAT, @@ -161,9 +156,9 @@ extern void free_dentry_private_data(struct dentry *dentry); extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); extern struct inode *sdcardfs_iget(struct super_block *sb, - struct inode *lower_inode); + struct inode *lower_inode, userid_t id); extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, - struct path *lower_path); + struct path *lower_path, userid_t id); /* file private data */ struct sdcardfs_file_info { @@ -174,18 +169,16 @@ struct sdcardfs_file_info { /* sdcardfs inode data in memory */ struct sdcardfs_inode_info { struct inode *lower_inode; - /* state derived based on current position in hierachy - * caution: d_mode does not include file types - */ + /* state derived based on current position in hierachy */ perm_t perm; userid_t userid; uid_t d_uid; - gid_t d_gid; - mode_t d_mode; + bool under_android; struct inode vfs_inode; }; + /* sdcardfs dentry data in memory */ struct sdcardfs_dentry_info { spinlock_t lock; /* protects lower_path */ @@ -196,15 +189,17 @@ struct sdcardfs_dentry_info { struct sdcardfs_mount_options { uid_t fs_low_uid; gid_t fs_low_gid; - gid_t write_gid; - int split_perms; - derive_t derive; + userid_t fs_user_id; + gid_t gid; lower_fs_t lower_fs; + mode_t mask; + bool multiuser; unsigned int reserved_mb; }; /* sdcardfs super-block data in memory */ struct sdcardfs_sb_info { + struct super_block *sb; struct super_block *lower_sb; /* derived perm policy : some of options have been added * to sdcardfs_mount_options (Android 4.4 support) */ @@ -213,6 +208,7 @@ struct sdcardfs_sb_info { char *obbpath_s; struct path obbpath; void *pkgl_id; + struct list_head list; }; /* @@ -331,6 +327,44 @@ static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ SDCARDFS_DENT_FUNC(lower_path) SDCARDFS_DENT_FUNC(orig_path) +static inline int get_gid(struct sdcardfs_inode_info *info) { + struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); + if (sb_info->options.gid == AID_SDCARD_RW) { + /* As an optimization, certain trusted system components only run + * as owner but operate across all users. Since we're now handing + * out the sdcard_rw GID only to trusted apps, we're okay relaxing + * the user boundary enforcement for the default view. The UIDs + * assigned to app directories are still multiuser aware. */ + return AID_SDCARD_RW; + } else { + return multiuser_get_uid(info->userid, sb_info->options.gid); + } +} +static inline int get_mode(struct sdcardfs_inode_info *info) { + int owner_mode; + int filtered_mode; + struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); + int visible_mode = 0775 & ~sb_info->options.mask; + + if (info->perm == PERM_PRE_ROOT) { + /* Top of multi-user view should always be visible to ensure + * secondary users can traverse inside. */ + visible_mode = 0711; + } else if (info->under_android) { + /* Block "other" access to Android directories, since only apps + * belonging to a specific user should be in there; we still + * leave +x open for the default view. */ + if (sb_info->options.gid == AID_SDCARD_RW) { + visible_mode = visible_mode & ~0006; + } else { + visible_mode = visible_mode & ~0007; + } + } + owner_mode = info->lower_inode->i_mode & 0700; + filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6)); + return filtered_mode; +} + static inline int has_graft_path(const struct dentry *dent) { int ret = 0; @@ -364,22 +398,24 @@ static inline void sdcardfs_put_real_lower(const struct dentry *dent, sdcardfs_put_lower_path(dent, real_lower); } +extern struct mutex sdcardfs_super_list_lock; +extern struct list_head sdcardfs_super_list; + /* for packagelist.c */ -extern int get_caller_has_rw_locked(void *pkgl_id, derive_t derive); extern appid_t get_appid(void *pkgl_id, const char *app_name); -extern int check_caller_access_to_name(struct inode *parent_node, const char* name, - derive_t derive, int w_ok, int has_rw); +extern int check_caller_access_to_name(struct inode *parent_node, const char* name); extern int open_flags_to_access_mode(int open_flags); -extern void * packagelist_create(gid_t write_gid); -extern void packagelist_destroy(void *pkgl_id); extern int packagelist_init(void); extern void packagelist_exit(void); /* for derived_perm.c */ extern void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, gid_t gid, mode_t mode); + userid_t userid, uid_t uid, bool under_android); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); -extern void update_derived_permission(struct dentry *dentry); +extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); +extern void get_derive_permissions_recursive(struct dentry *parent); + +extern void update_derived_permission_lock(struct dentry *dentry); extern int need_graft_path(struct dentry *dentry); extern int is_base_obbpath(struct dentry *dentry); extern int is_obbpath_invalid(struct dentry *dentry); @@ -483,4 +519,18 @@ static inline int check_min_free_space(struct dentry *dentry, size_t size, int d return 1; } +/* Copies attrs and maintains sdcardfs managed attrs */ +static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src) +{ + dest->i_mode = (src->i_mode & S_IFMT) | get_mode(SDCARDFS_I(dest)); + dest->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(dest)->d_uid); + dest->i_gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(dest))); + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_flags = src->i_flags; + set_nlink(dest, src->i_nlink); +} #endif /* not _SDCARDFS_H_ */ diff --git a/fs/sdcardfs/strtok.h b/fs/sdcardfs/strtok.h deleted file mode 100644 index 50ab25aa0bc4..000000000000 --- a/fs/sdcardfs/strtok.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * fs/sdcardfs/strtok.h - * - * Copyright (c) 2013 Samsung Electronics Co. Ltd - * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, - * Sunghwan Yun, Sungjong Seo - * - * This program has been developed as a stackable file system based on - * the WrapFS which written by - * - * Copyright (c) 1998-2011 Erez Zadok - * Copyright (c) 2009 Shrikar Archak - * Copyright (c) 2003-2011 Stony Brook University - * Copyright (c) 2003-2011 The Research Foundation of SUNY - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - */ - -static char * -strtok_r(char *s, const char *delim, char **last) -{ - char *spanp; - int c, sc; - char *tok; - - - /* if (s == NULL && (s = *last) == NULL) - return NULL; */ - if (s == NULL) { - s = *last; - if (s == NULL) - return NULL; - } - - /* - * Skip (span) leading delimiters (s += strspn(s, delim), sort of). - */ -cont: - c = *s++; - for (spanp = (char *)delim; (sc = *spanp++) != 0;) { - if (c == sc) - goto cont; - } - - if (c == 0) { /* no non-delimiter characters */ - *last = NULL; - return NULL; - } - tok = s - 1; - - /* - * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). - * Note that delim must have one NUL; we stop if we see that, too. - */ - for (;;) { - c = *s++; - spanp = (char *)delim; - do { - sc = *spanp++; - if (sc == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *last = s; - return tok; - } - } while (sc != 0); - } - - /* NOTREACHED */ -} - diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index f153ce1b8cf3..1d6490128c99 100644 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -46,9 +46,6 @@ static void sdcardfs_put_super(struct super_block *sb) sdcardfs_set_lower_super(sb, NULL); atomic_dec(&s->s_active); - if(spd->pkgl_id) - packagelist_destroy(spd->pkgl_id); - kfree(spd); sb->s_fs_info = NULL; } @@ -203,12 +200,8 @@ static int sdcardfs_show_options(struct seq_file *m, struct dentry *root) if (opts->fs_low_gid != 0) seq_printf(m, ",gid=%u", opts->fs_low_gid); - if (opts->derive == DERIVE_NONE) - seq_printf(m, ",derive=none"); - else if (opts->derive == DERIVE_LEGACY) - seq_printf(m, ",derive=legacy"); - else if (opts->derive == DERIVE_UNIFIED) - seq_printf(m, ",derive=unified"); + if (opts->multiuser) + seq_printf(m, ",multiuser"); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb);