ci->userid = pi->userid;
ci->d_uid = pi->d_uid;
ci->under_android = pi->under_android;
+ set_top(ci, pi->top);
}
/* helper function for derived state */
-void setup_derived_state(struct inode *inode, perm_t perm,
- userid_t userid, uid_t uid, bool under_android)
+void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
+ uid_t uid, bool under_android, struct inode *top)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
info->userid = userid;
info->d_uid = uid;
info->under_android = under_android;
+ set_top(info, top);
}
/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */
/* Legacy internal layout places users at top level */
info->perm = PERM_ROOT;
info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10);
+ set_top(info, &info->vfs_inode);
break;
case PERM_ROOT:
/* Assume masked off by default. */
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID;
info->under_android = true;
+ set_top(info, &info->vfs_inode);
}
break;
case PERM_ANDROID:
if (!strcasecmp(newdentry->d_name.name, "data")) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_DATA;
+ set_top(info, &info->vfs_inode);
} else if (!strcasecmp(newdentry->d_name.name, "obb")) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_OBB;
+ set_top(info, &info->vfs_inode);
/* Single OBB directory is always shared */
} else if (!strcasecmp(newdentry->d_name.name, "media")) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_MEDIA;
+ set_top(info, &info->vfs_inode);
}
break;
case PERM_ANDROID_DATA:
if (appid != 0) {
info->d_uid = multiuser_get_uid(parent_info->userid, appid);
}
+ set_top(info, &info->vfs_inode);
break;
}
}
get_derived_permission_new(parent, dentry, dentry);
}
-void get_derive_permissions_recursive(struct dentry *parent) {
+static int descendant_may_need_fixup(perm_t perm) {
+ if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID)
+ return 1;
+ return 0;
+}
+
+static int needs_fixup(perm_t perm) {
+ if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB
+ || perm == PERM_ANDROID_MEDIA)
+ return 1;
+ return 0;
+}
+
+void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) {
+ struct dentry *child;
+ struct sdcardfs_inode_info *info;
+ if (!dget(dentry))
+ return;
+ if (!dentry->d_inode) {
+ dput(dentry);
+ return;
+ }
+ info = SDCARDFS_I(dentry->d_inode);
+
+ if (needs_fixup(info->perm)) {
+ mutex_lock(&dentry->d_inode->i_mutex);
+ child = lookup_one_len(name, dentry, len);
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ if (!IS_ERR(child)) {
+ if (child->d_inode) {
+ get_derived_permission(dentry, child);
+ fix_derived_permission(child->d_inode);
+ }
+ dput(child);
+ }
+ } else if (descendant_may_need_fixup(info->perm)) {
+ mutex_lock(&dentry->d_inode->i_mutex);
+ list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
+ fixup_perms_recursive(child, name, len);
+ }
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ }
+ dput(dentry);
+}
+
+void fixup_top_recursive(struct dentry *parent) {
struct dentry *dentry;
+ struct sdcardfs_inode_info *info;
+ if (!parent->d_inode)
+ return;
+ info = SDCARDFS_I(parent->d_inode);
spin_lock(&parent->d_lock);
list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
if (dentry->d_inode) {
- get_derived_permission(parent, dentry);
- fix_derived_permission(dentry->d_inode);
- get_derive_permissions_recursive(dentry);
+ if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) {
+ get_derived_permission(parent, dentry);
+ fix_derived_permission(dentry->d_inode);
+ fixup_top_recursive(dentry);
+ }
}
}
spin_unlock(&parent->d_lock);
* we pass along new_dentry for the name.*/
get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry);
fix_derived_permission(old_dentry->d_inode);
- get_derive_permissions_recursive(old_dentry);
+ fixup_top_recursive(old_dentry);
out:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_old_dir_dentry);
static int sdcardfs_permission(struct inode *inode, int mask)
{
int err;
+ struct inode *top = grab_top(SDCARDFS_I(inode));
+
+ if (!top)
+ return -EINVAL;
+ /* Ensure owner is up to date */
+ if (!uid_eq(inode->i_uid, top->i_uid)) {
+ SDCARDFS_I(inode)->d_uid = SDCARDFS_I(top)->d_uid;
+ fix_derived_permission(inode);
+ }
+ release_top(SDCARDFS_I(inode));
/*
* Permission check on sdcardfs inode.
}
-static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
-{
- struct dentry *lower_dentry;
- struct inode *inode;
- struct inode *lower_inode;
- struct path lower_path;
- struct dentry *parent;
-
- parent = dget_parent(dentry);
- 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);
- dput(parent);
- return -EACCES;
- }
- dput(parent);
-
- inode = dentry->d_inode;
-
- sdcardfs_get_lower_path(dentry, &lower_path);
- lower_dentry = lower_path.dentry;
- lower_inode = sdcardfs_lower_inode(inode);
-
-
- sdcardfs_copy_and_fix_attrs(inode, lower_inode);
- fsstack_copy_inode_size(inode, lower_inode);
-
-
- generic_fillattr(inode, stat);
- sdcardfs_put_lower_path(dentry, &lower_path);
- return 0;
-}
-
static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
{
int err = 0;
return err;
}
+static int sdcardfs_fillattr(struct inode *inode, struct kstat *stat)
+{
+ struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
+ struct inode *top = grab_top(info);
+ if (!top)
+ return -EINVAL;
+
+ stat->dev = inode->i_sb->s_dev;
+ stat->ino = inode->i_ino;
+ stat->mode = (inode->i_mode & S_IFMT) | get_mode(SDCARDFS_I(top));
+ stat->nlink = inode->i_nlink;
+ stat->uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
+ stat->gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(top)));
+ stat->rdev = inode->i_rdev;
+ stat->size = i_size_read(inode);
+ stat->atime = inode->i_atime;
+ stat->mtime = inode->i_mtime;
+ stat->ctime = inode->i_ctime;
+ stat->blksize = (1 << inode->i_blkbits);
+ stat->blocks = inode->i_blocks;
+ release_top(info);
+ return 0;
+}
+
+static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ struct dentry *lower_dentry;
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct path lower_path;
+ struct dentry *parent;
+ int err;
+
+ parent = dget_parent(dentry);
+ 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);
+ dput(parent);
+ return -EACCES;
+ }
+ dput(parent);
+
+ inode = dentry->d_inode;
+
+ sdcardfs_get_lower_path(dentry, &lower_path);
+ lower_dentry = lower_path.dentry;
+ lower_inode = sdcardfs_lower_inode(inode);
+
+ sdcardfs_copy_and_fix_attrs(inode, lower_inode);
+ fsstack_copy_inode_size(inode, lower_inode);
+
+ err = sdcardfs_fillattr(inode, stat);
+ sdcardfs_put_lower_path(dentry, &lower_path);
+ return err;
+}
+
const struct inode_operations sdcardfs_symlink_iops = {
.permission = sdcardfs_permission,
.setattr = sdcardfs_setattr,
const struct inode_operations sdcardfs_dir_iops = {
.create = sdcardfs_create,
.lookup = sdcardfs_lookup,
-#if 0
.permission = sdcardfs_permission,
-#endif
.unlink = sdcardfs_unlink,
.mkdir = sdcardfs_mkdir,
.rmdir = sdcardfs_rmdir,
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);
+ setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode);
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, 00664);*/
} else {
- setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false);
+ setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false, sb->s_root->d_inode);
snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
}
fix_derived_permission(sb->s_root->d_inode);
return 0;
}
-static void fixup_perms(struct super_block *sb) {
+static void fixup_perms(struct super_block *sb, const char *key) {
if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) {
- get_derive_permissions_recursive(sb->s_root);
+ fixup_perms_recursive(sb->s_root, key, strlen(key));
}
}
-static void fixup_all_perms(void)
+static void fixup_all_perms(const char *key)
{
struct sdcardfs_sb_info *sbinfo;
list_for_each_entry(sbinfo, &sdcardfs_super_list, list)
if (sbinfo)
- fixup_perms(sbinfo->sb);
+ fixup_perms(sbinfo->sb, key);
}
static int insert_packagelist_entry(const char *key, appid_t value)
mutex_lock(&sdcardfs_super_list_lock);
err = insert_packagelist_entry_locked(key, value);
if (!err)
- fixup_all_perms();
+ fixup_all_perms(key);
mutex_unlock(&sdcardfs_super_list_lock);
return err;
{
mutex_lock(&sdcardfs_super_list_lock);
remove_packagelist_entry_locked(key);
- fixup_all_perms();
+ fixup_all_perms(key);
mutex_unlock(&sdcardfs_super_list_lock);
return;
}
userid_t userid;
uid_t d_uid;
bool under_android;
+ /* top folder for ownership */
+ struct inode *top;
struct inode vfs_inode;
};
SDCARDFS_DENT_FUNC(lower_path)
SDCARDFS_DENT_FUNC(orig_path)
+/* grab a refererence if we aren't linking to ourself */
+static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top)
+{
+ struct inode *old_top = NULL;
+ BUG_ON(IS_ERR_OR_NULL(top));
+ if (info->top && info->top != &info->vfs_inode) {
+ old_top = info->top;
+ }
+ if (top != &info->vfs_inode)
+ igrab(top);
+ info->top = top;
+ iput(old_top);
+}
+
+static inline struct inode *grab_top(struct sdcardfs_inode_info *info)
+{
+ struct inode *top = info->top;
+ if (top) {
+ return igrab(top);
+ } else {
+ return NULL;
+ }
+}
+
+static inline void release_top(struct sdcardfs_inode_info *info)
+{
+ iput(info->top);
+}
+
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) {
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);
+ 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) {
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, bool under_android);
+extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
+ uid_t uid, bool under_android, struct inode *top);
extern void get_derived_permission(struct dentry *parent, 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 fixup_top_recursive(struct dentry *parent);
+extern void fixup_perms_recursive(struct dentry *dentry, const char *name, size_t len);
extern void update_derived_permission_lock(struct dentry *dentry);
extern int need_graft_path(struct dentry *dentry);
*/
lower_inode = sdcardfs_lower_inode(inode);
sdcardfs_set_lower_inode(inode, NULL);
+ set_top(SDCARDFS_I(inode), inode);
iput(lower_inode);
}