In M, the workings of sdcardfs were changed significantly.
This brings sdcardfs into line with the changes.
Change-Id: I10e91a84a884c838feef7aa26c0a2b21f02e052e
config SDCARD_FS
tristate "sdcard file system"
+ depends on CONFIGFS_FS
default n
help
Sdcardfs is based on Wrapfs file system.
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);
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_u.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;
* 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 {
}
}
fix_derived_permission(dentry->d_inode);
+ mutex_unlock(&dentry->d_inode->i_mutex);
}
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;
}
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) ||
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;
}
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
* 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;
}
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)) {
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);
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:
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);
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));
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);
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);
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;
/* 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;
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);
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);
goto out;
/* Copy attrs from lower dir, but i_uid/i_gid */
- fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
+ sdcardfs_copy_and_fix_attrs(new_dir, lower_new_dir_dentry->d_inode);
fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode);
- fix_derived_permission(new_dir);
+
if (new_dir != old_dir) {
- fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+ sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode);
fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode);
- 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(old_dentry->d_inode) {
- get_derived_permission(new_parent, old_dentry);
- fix_derived_permission(old_dentry->d_inode);
+ 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(&old_dentry->d_inode->i_mutex);
+ 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);
+ mutex_unlock(&old_dentry->d_inode->i_mutex);
out:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_old_dir_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(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)) {
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);
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);
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 = dentry->d_inode;
/* 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(parent->d_inode, dentry->d_name.name,
- sbi->options.derive, 1, 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);
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
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 */
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
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);
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;
}
* @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;
*/
/* 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;
}
* Fills in lower_parent_path with <dentry,mnt> 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;
}
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;
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",
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;
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,
#include <linux/parser.h>
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}
};
/* 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 */
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]);
}
#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.
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");
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;
}
}
sb_info = sb->s_fs_info;
-
/* parse options */
err = parse_options(sb, raw_data, silent, &debug, &sb_info->options);
if (err) {
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);
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;
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, 00664);
- 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, 00664);*/
+ } 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",
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;
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,
};
*/
#include "sdcardfs.h"
-#include "strtok.h"
#include <linux/hashtable.h>
-#include <linux/syscalls.h>
-#include <linux/kthread.h>
-#include <linux/inotify.h>
#include <linux/delay.h>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/configfs.h>
+
#define STRING_BUF_SIZE (512)
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;
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(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) {
}
}
- /* 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 (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 &&
- (current_fsuid() == SDCARDFS_I(parent_node)->d_uid)) {
- return 1;
- }
- return has_rw;
- }
-
/* No extra permissions to enforce */
return 1;
}
}
}
-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;
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 struct configfs_attribute package_appid_attr_add_pid = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "appid",
+ .ca_mode = S_IRUGO | S_IWUGO,
+};
+
+static struct configfs_attribute *package_appid_attrs[] = {
+ &package_appid_attr_add_pid,
+ NULL,
+};
+
+static ssize_t package_appid_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ 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,
+ struct configfs_attribute *attr,
+ 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 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));
+}
- 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_item_operations package_appid_item_ops = {
+ .release = package_appid_release,
+ .show_attribute = package_appid_attr_show,
+ .store_attribute = package_appid_attr_store,
+};
- event_size = sizeof(*event) + event->len;
- res -= event_size;
- event_pos += event_size;
- }
- continue;
+static struct config_item_type package_appid_type = {
+ .ct_item_ops = &package_appid_item_ops,
+ .ct_attrs = package_appid_attrs,
+ .ct_owner = THIS_MODULE,
+};
-interruptable_sleep:
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- flush_signals(current);
- sys_close(nfd);
- return res;
+
+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 struct configfs_attribute sdcardfs_packages_attr_description = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "packages_gid.list",
+ .ca_mode = S_IRUGO,
+};
- return (void *)pkgl_dat;
+static struct configfs_attribute *sdcardfs_packages_attrs[] = {
+ &sdcardfs_packages_attr_description,
+ NULL,
+};
+
+static ssize_t packages_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ 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 count;
}
-void packagelist_destroy(void *pkgl_id)
+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,
+ .show_attribute = packages_attr_show,
+};
+
+/*
+ * 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)
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);
}
-
-
#include <linux/types.h>
#include <linux/security.h>
#include <linux/string.h>
+#include <linux/list.h>
#include "multiuser.h"
/* the file system name */
#define fix_derived_permission(x) \
do { \
(x)->i_uid = SDCARDFS_I(x)->d_uid; \
- (x)->i_gid = SDCARDFS_I(x)->d_gid; \
- (x)->i_mode = ((x)->i_mode & S_IFMT) | SDCARDFS_I(x)->d_mode;\
+ (x)->i_gid = 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
(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,
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 {
/* 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 */
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) */
char *obbpath_s;
struct path obbpath;
void *pkgl_id;
+ struct list_head list;
};
/*
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;
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);
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 = SDCARDFS_I(dest)->d_uid;
+ dest->i_gid = 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_ */
+++ /dev/null
-/*
- * 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 */
-}
-
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;
}
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);