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
This commit is contained in:
Daniel Rosenberg 2016-02-03 21:08:21 -08:00 committed by Amit Pundir
parent ca275513ce
commit da3341e655
10 changed files with 518 additions and 629 deletions

View file

@ -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.

View file

@ -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 &&
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;
}
/* 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)) {
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;
}

View file

@ -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:

View file

@ -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);

View file

@ -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 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
* 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;
@ -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,

View file

@ -24,25 +24,27 @@
#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}
};
@ -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 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
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,
};

View file

@ -19,13 +19,16 @@
*/
#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 {
@ -34,25 +37,20 @@ struct hashtable_entry {
unsigned int value;
};
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];
struct sb_list {
struct super_block *sb;
struct list_head list;
};
static struct kmem_cache *hashtable_entry_cachep;
struct packagelist_data {
DECLARE_HASHTABLE(package_to_appid,8);
struct mutex hashtable_lock;
/* 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 packagelist_data *pkgl_data_all;
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,247 +142,277 @@ 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;
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);
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;
printk(KERN_INFO "sdcardfs: read_package_list\n");
mutex_lock(&pkgl_dat->hashtable_lock);
remove_all_hashentrys(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;
}
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);
}
}
}
sys_close(fd);
hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist)
remove_str_to_int_lock(hash_cur);
mutex_unlock(&pkgl_dat->hashtable_lock);
return 0;
hash_init(pkgl_dat->package_to_appid);
}
static int packagelist_reader(void *thread_data)
{
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;
}
while (!kthread_should_stop()) {
if (signal_pending(current)) {
ssleep(1);
continue;
}
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;
}
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;
}
while (res >= (int) sizeof(*event)) {
event = (struct inotify_event *) (pkgl_dat->event_buf + event_pos);
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;
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
continue;
interruptable_sleep:
set_current_state(TASK_INTERRUPTIBLE);
schedule();
}
flush_signals(current);
sys_close(nfd);
return res;
}
void * packagelist_create(gid_t write_gid)
static struct packagelist_data * packagelist_create(void)
{
struct packagelist_data *pkgl_dat;
struct task_struct *packagelist_thread;
pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO);
if (!pkgl_dat) {
printk(KERN_ERR "sdcardfs: creating kthread failed\n");
printk(KERN_ERR "sdcardfs: Failed to create hash\n");
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;
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;
printk(KERN_INFO "sdcardfs: created packagelist pkgld/%d\n",
(int)pkgl_dat->thread_id->pid);
return (void *)pkgl_dat;
return pkgl_dat;
}
void packagelist_destroy(void *pkgl_id)
static void packagelist_destroy(struct packagelist_data *pkgl_dat)
{
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);
printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n");
kfree(pkgl_dat);
}
struct package_appid {
struct config_item item;
int add_pid;
};
static inline struct package_appid *to_package_appid(struct config_item *item)
{
return item ? container_of(item, struct package_appid, item) : NULL;
}
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 ssize_t package_appid_attr_store(struct config_item *item,
const char *page, size_t count)
{
struct package_appid *package_appid = to_package_appid(item);
unsigned long tmp;
char *p = (char *) page;
int ret;
tmp = simple_strtoul(p, &p, 10);
if (!p || (*p && (*p != '\n')))
return -EINVAL;
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;
return count;
}
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,
};
static struct configfs_attribute *package_appid_attrs[] = {
&package_appid_attr_add_pid,
NULL,
};
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));
}
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;
}
static struct config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name)
{
struct package_appid *package_appid;
package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL);
if (!package_appid)
return ERR_PTR(-ENOMEM);
config_item_init_type_name(&package_appid->item, name,
&package_appid_type);
package_appid->add_pid = 0;
return &package_appid->item;
}
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 count;
}
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)
{
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)
{
hashtable_entry_cachep =
@ -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);
}

View file

@ -42,6 +42,7 @@
#include <linux/types.h>
#include <linux/security.h>
#include <linux/string.h>
#include <linux/list.h>
#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_ */

View file

@ -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 */
}

View file

@ -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);