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:
parent
ca275513ce
commit
da3341e655
10 changed files with 518 additions and 629 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue