ci->userid = pi->userid;
ci->d_uid = pi->d_uid;
ci->under_android = pi->under_android;
+ ci->under_cache = pi->under_cache;
+ ci->under_obb = pi->under_obb;
set_top(ci, pi->top);
}
info->userid = userid;
info->d_uid = uid;
info->under_android = under_android;
+ info->under_cache = false;
+ info->under_obb = false;
set_top(info, top);
}
/* 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)
+void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const char *name)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
struct sdcardfs_inode_info *parent_info= SDCARDFS_I(d_inode(parent));
* the properties are maintained on its private fields
* because the inode attributes will be modified with that of
* its lower inode.
- * The derived state will be updated on the last
- * stage of each system call by fix_derived_permission(inode).
+ * These values are used by our custom permission call instead
+ * of using the inode permissions.
*/
inherit_derived_state(d_inode(parent), d_inode(dentry));
+ /* Files don't get special labels */
+ if (!S_ISDIR(d_inode(dentry)->i_mode))
+ return;
/* Derive custom permissions based on parent and current node */
switch (parent_info->perm) {
- case PERM_INHERIT:
- /* Already inherited above */
- break;
- case PERM_PRE_ROOT:
- /* Legacy internal layout places users at top level */
- info->perm = PERM_ROOT;
- info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10);
+ case PERM_INHERIT:
+ case PERM_ANDROID_PACKAGE_CACHE:
+ /* Already inherited above */
+ break;
+ case PERM_PRE_ROOT:
+ /* Legacy internal layout places users at top level */
+ info->perm = PERM_ROOT;
+ info->userid = simple_strtoul(name, NULL, 10);
+ set_top(info, &info->vfs_inode);
+ break;
+ case PERM_ROOT:
+ /* Assume masked off by default. */
+ if (!strcasecmp(name, "Android")) {
+ /* App-specific directories inside; let anyone traverse */
+ info->perm = PERM_ANDROID;
+ info->under_android = true;
set_top(info, &info->vfs_inode);
- break;
- case PERM_ROOT:
- /* Assume masked off by default. */
- if (!strcasecmp(newdentry->d_name.name, "Android")) {
- /* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID;
- info->under_android = true;
- set_top(info, &info->vfs_inode);
- }
- break;
- case PERM_ANDROID:
- if (!strcasecmp(newdentry->d_name.name, "data")) {
- /* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID_DATA;
- set_top(info, &info->vfs_inode);
- } else if (!strcasecmp(newdentry->d_name.name, "obb")) {
- /* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID_OBB;
- set_top(info, &info->vfs_inode);
- /* Single OBB directory is always shared */
- } else if (!strcasecmp(newdentry->d_name.name, "media")) {
- /* App-specific directories inside; let anyone traverse */
- info->perm = PERM_ANDROID_MEDIA;
- set_top(info, &info->vfs_inode);
- }
- break;
- case PERM_ANDROID_DATA:
- case PERM_ANDROID_OBB:
- case PERM_ANDROID_MEDIA:
- appid = get_appid(newdentry->d_name.name);
- if (appid != 0 && !is_excluded(newdentry->d_name.name, parent_info->userid)) {
- info->d_uid = multiuser_get_uid(parent_info->userid, appid);
- }
+ }
+ break;
+ case PERM_ANDROID:
+ if (!strcasecmp(name, "data")) {
+ /* App-specific directories inside; let anyone traverse */
+ info->perm = PERM_ANDROID_DATA;
+ set_top(info, &info->vfs_inode);
+ } else if (!strcasecmp(name, "obb")) {
+ /* App-specific directories inside; let anyone traverse */
+ info->perm = PERM_ANDROID_OBB;
+ info->under_obb = true;
set_top(info, &info->vfs_inode);
- break;
+ /* Single OBB directory is always shared */
+ } else if (!strcasecmp(name, "media")) {
+ /* App-specific directories inside; let anyone traverse */
+ info->perm = PERM_ANDROID_MEDIA;
+ set_top(info, &info->vfs_inode);
+ }
+ break;
+ case PERM_ANDROID_OBB:
+ case PERM_ANDROID_DATA:
+ case PERM_ANDROID_MEDIA:
+ info->perm = PERM_ANDROID_PACKAGE;
+ appid = get_appid(name);
+ if (appid != 0 && !is_excluded(name, parent_info->userid)) {
+ info->d_uid = multiuser_get_uid(parent_info->userid, appid);
+ }
+ set_top(info, &info->vfs_inode);
+ break;
+ case PERM_ANDROID_PACKAGE:
+ if (!strcasecmp(name, "cache")) {
+ info->perm = PERM_ANDROID_PACKAGE_CACHE;
+ info->under_cache = true;
+ }
+ break;
}
}
void get_derived_permission(struct dentry *parent, struct dentry *dentry)
{
- get_derived_permission_new(parent, dentry, dentry);
+ get_derived_permission_new(parent, dentry, dentry->d_name.name);
+}
+
+static appid_t get_type(const char *name)
+{
+ const char *ext = strrchr(name, '.');
+ appid_t id;
+
+ if (ext && ext[0]) {
+ ext = &ext[1];
+ id = get_ext_gid(ext);
+ return id?:AID_MEDIA_RW;
+ }
+ return AID_MEDIA_RW;
+}
+
+void fixup_lower_ownership(struct dentry *dentry, const char *name)
+{
+ struct path path;
+ struct inode *inode;
+ struct inode *delegated_inode = NULL;
+ int error;
+ struct sdcardfs_inode_info *info;
+ struct sdcardfs_inode_info *info_top;
+ perm_t perm;
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+ uid_t uid = sbi->options.fs_low_uid;
+ gid_t gid = sbi->options.fs_low_gid;
+ struct iattr newattrs;
+
+ info = SDCARDFS_I(d_inode(dentry));
+ perm = info->perm;
+ if (info->under_obb) {
+ perm = PERM_ANDROID_OBB;
+ } else if (info->under_cache) {
+ perm = PERM_ANDROID_PACKAGE_CACHE;
+ } else if (perm == PERM_INHERIT) {
+ info_top = SDCARDFS_I(grab_top(info));
+ perm = info_top->perm;
+ release_top(info);
+ }
+
+ switch (perm) {
+ case PERM_ROOT:
+ case PERM_ANDROID:
+ case PERM_ANDROID_DATA:
+ case PERM_ANDROID_MEDIA:
+ case PERM_ANDROID_PACKAGE:
+ case PERM_ANDROID_PACKAGE_CACHE:
+ uid = multiuser_get_uid(info->userid, uid);
+ break;
+ case PERM_ANDROID_OBB:
+ uid = AID_MEDIA_OBB;
+ break;
+ case PERM_PRE_ROOT:
+ default:
+ break;
+ }
+ switch (perm) {
+ case PERM_ROOT:
+ case PERM_ANDROID:
+ case PERM_ANDROID_DATA:
+ case PERM_ANDROID_MEDIA:
+ if (S_ISDIR(d_inode(dentry)->i_mode))
+ gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
+ else
+ gid = multiuser_get_uid(info->userid, get_type(name));
+ break;
+ case PERM_ANDROID_OBB:
+ gid = AID_MEDIA_OBB;
+ break;
+ case PERM_ANDROID_PACKAGE:
+ if (info->d_uid != 0)
+ gid = multiuser_get_ext_gid(info->userid, info->d_uid);
+ else
+ gid = multiuser_get_uid(info->userid, uid);
+ break;
+ case PERM_ANDROID_PACKAGE_CACHE:
+ if (info->d_uid != 0)
+ gid = multiuser_get_cache_gid(info->userid, info->d_uid);
+ else
+ gid = multiuser_get_uid(info->userid, uid);
+ break;
+ case PERM_PRE_ROOT:
+ default:
+ break;
+ }
+
+ sdcardfs_get_lower_path(dentry, &path);
+ inode = d_inode(path.dentry);
+ if (d_inode(path.dentry)->i_gid.val != gid || d_inode(path.dentry)->i_uid.val != uid) {
+retry_deleg:
+ newattrs.ia_valid = ATTR_GID | ATTR_UID | ATTR_FORCE;
+ newattrs.ia_uid = make_kuid(current_user_ns(), uid);
+ newattrs.ia_gid = make_kgid(current_user_ns(), gid);
+ if (!S_ISDIR(inode->i_mode))
+ newattrs.ia_valid |=
+ ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
+ inode_lock(inode);
+ error = security_path_chown(&path, newattrs.ia_uid, newattrs.ia_gid);
+ if (!error)
+ error = notify_change2(path.mnt, path.dentry, &newattrs, &delegated_inode);
+ inode_unlock(inode);
+ if (delegated_inode) {
+ error = break_deleg_wait(&delegated_inode);
+ if (!error)
+ goto retry_deleg;
+ }
+ if (error)
+ pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n");
+ }
}
static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit)
dput(dentry);
}
-void fixup_top_recursive(struct dentry *parent) {
+void drop_recursive(struct dentry *parent)
+{
struct dentry *dentry;
struct sdcardfs_inode_info *info;
+ if (!d_inode(parent))
+ return;
+ info = SDCARDFS_I(d_inode(parent));
+ spin_lock(&parent->d_lock);
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
+ if (d_inode(dentry)) {
+ if (SDCARDFS_I(d_inode(parent))->top != SDCARDFS_I(d_inode(dentry))->top) {
+ drop_recursive(dentry);
+ d_drop(dentry);
+ }
+ }
+ }
+ spin_unlock(&parent->d_lock);
+}
+
+void fixup_top_recursive(struct dentry *parent)
+{
+ struct dentry *dentry;
+ struct sdcardfs_inode_info *info;
+
if (!d_inode(parent))
return;
info = SDCARDFS_I(d_inode(parent));
}
/* save current_cred and override it */
- OVERRIDE_CRED(sbi, saved_cred);
+ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode));
file->private_data =
kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL);
#include <linux/fs_struct.h>
/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
-const struct cred * override_fsids(struct sdcardfs_sb_info* sbi)
+const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_info *info)
{
- struct cred * cred;
- const struct cred * old_cred;
+ struct cred *cred;
+ const struct cred *old_cred;
+ uid_t uid;
cred = prepare_creds();
if (!cred)
return NULL;
- cred->fsuid = make_kuid(&init_user_ns, sbi->options.fs_low_uid);
+ if (info->under_obb)
+ uid = AID_MEDIA_OBB;
+ else
+ uid = multiuser_get_uid(info->userid, sbi->options.fs_low_uid);
+ cred->fsuid = make_kuid(&init_user_ns, uid);
cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid);
old_cred = override_creds(cred);
}
/* Do not directly use this function, use REVERT_CRED() instead. */
-void revert_fsids(const struct cred * old_cred)
+void revert_fsids(const struct cred *old_cred)
{
- const struct cred * cur_cred;
+ const struct cred *cur_cred;
cur_cred = current->cred;
revert_creds(old_cred);
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
sdcardfs_get_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
goto out;
fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
+ fixup_lower_ownership(dentry, dentry->d_name.name);
out:
current->fs = saved_fs;
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
sdcardfs_get_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
/* check disk space */
if (!check_min_free_space(dentry, 0, 1)) {
fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
/* update number of links on parent directory */
set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink);
-
+ fixup_lower_ownership(dentry, dentry->d_name.name);
unlock_dir(lower_parent_dentry);
-
if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb"))
&& (pi->perm == PERM_ANDROID) && (pi->userid == 0))
make_nomedia_in_obb = 1;
/* When creating /Android/data and /Android/obb, mark them as .nomedia */
if (make_nomedia_in_obb ||
((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) {
+ REVERT_CRED(saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(d_inode(dentry)));
set_fs_pwd(current->fs, &lower_path);
touch_err = touch(".nomedia", 0664);
if (touch_err) {
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
/* sdcardfs_get_real_lower(): in case of remove an user's obb dentry
* the dentry on the original path should be deleted. */
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred, SDCARDFS_I(new_dir));
sdcardfs_get_real_lower(old_dentry, &lower_old_path);
sdcardfs_get_lower_path(new_dentry, &lower_new_path);
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));
}
- /* At this point, not all dentry information has been moved, so
- * we pass along new_dentry for the name.*/
- get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry);
+ get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry->d_name.name);
fixup_tmp_permissions(d_inode(old_dentry));
- fixup_top_recursive(old_dentry);
+ fixup_lower_ownership(old_dentry, new_dentry->d_name.name);
+ drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */
out:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_old_dir_dentry);
goto out_err;
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred);
+ OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode));
sdcardfs_get_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
}
/* save current_cred and override it */
- OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred);
+ OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
sdcardfs_get_lower_path(parent, &lower_parent_path);
/* get derived permission */
get_derived_permission(parent, dentry);
fixup_tmp_permissions(d_inode(dentry));
+ fixup_lower_ownership(dentry, dentry->d_name.name);
}
/* update parent directory's atime */
fsstack_copy_attr_atime(d_inode(parent),
* General Public License.
*/
-#define MULTIUSER_APP_PER_USER_RANGE 100000
+#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */
+#define AID_APP_START 10000 /* first app user */
+#define AID_APP_END 19999 /* last app user */
+#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */
+#define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */
+#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
typedef uid_t userid_t;
typedef uid_t appid_t;
-static inline userid_t multiuser_get_user_id(uid_t uid) {
- return uid / MULTIUSER_APP_PER_USER_RANGE;
+static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id)
+{
+ return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
}
-static inline appid_t multiuser_get_app_id(uid_t uid) {
- return uid % MULTIUSER_APP_PER_USER_RANGE;
+static inline gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id)
+{
+ if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+ return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START);
+ } else {
+ return -1;
+ }
}
-static inline uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
- return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
+static inline gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id)
+{
+ if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+ return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START);
+ } else {
+ return -1;
+ }
}
-
#include "sdcardfs.h"
#include <linux/hashtable.h>
#include <linux/delay.h>
+#include <linux/radix-tree.h>
#include <linux/init.h>
static DEFINE_HASHTABLE(package_to_appid, 8);
static DEFINE_HASHTABLE(package_to_userid, 8);
+static DEFINE_HASHTABLE(ext_to_groupid, 8);
+
static struct kmem_cache *hashtable_entry_cachep;
return h;
}
-appid_t get_appid(const char *app_name)
+appid_t get_appid(const char *key)
{
struct hashtable_entry *hash_cur;
- unsigned int hash = str_hash(app_name);
+ unsigned int hash = str_hash(key);
appid_t ret_id;
rcu_read_lock();
hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) {
- if (!strcasecmp(app_name, hash_cur->key)) {
+ if (!strcasecmp(key, hash_cur->key)) {
+ ret_id = atomic_read(&hash_cur->value);
+ rcu_read_unlock();
+ return ret_id;
+ }
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+appid_t get_ext_gid(const char *key)
+{
+ struct hashtable_entry *hash_cur;
+ unsigned int hash = str_hash(key);
+ appid_t ret_id;
+
+ rcu_read_lock();
+ hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) {
+ if (!strcasecmp(key, hash_cur->key)) {
ret_id = atomic_read(&hash_cur->value);
rcu_read_unlock();
return ret_id;
/* 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) {
-
+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) {
if (!strcasecmp(name, "autorun.inf")
}
}
-static struct hashtable_entry *alloc_packagelist_entry(const char *key,
+static struct hashtable_entry *alloc_hashtable_entry(const char *key,
appid_t value)
{
struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep,
return 0;
}
}
- new_entry = alloc_packagelist_entry(key, value);
+ new_entry = alloc_hashtable_entry(key, value);
if (!new_entry)
return -ENOMEM;
hash_add_rcu(package_to_appid, &new_entry->hlist, hash);
return 0;
}
+static int insert_ext_gid_entry_locked(const char *key, appid_t value)
+{
+ struct hashtable_entry *hash_cur;
+ struct hashtable_entry *new_entry;
+ unsigned int hash = str_hash(key);
+
+ /* An extension can only belong to one gid */
+ hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) {
+ if (!strcasecmp(key, hash_cur->key))
+ return -EINVAL;
+ }
+ new_entry = alloc_hashtable_entry(key, value);
+ if (!new_entry)
+ return -ENOMEM;
+ hash_add_rcu(ext_to_groupid, &new_entry->hlist, hash);
+ return 0;
+}
+
static int insert_userid_exclude_entry_locked(const char *key, userid_t value)
{
struct hashtable_entry *hash_cur;
if (atomic_read(&hash_cur->value) == value && !strcasecmp(key, hash_cur->key))
return 0;
}
- new_entry = alloc_packagelist_entry(key, value);
+ new_entry = alloc_hashtable_entry(key, value);
if (!new_entry)
return -ENOMEM;
hash_add_rcu(package_to_userid, &new_entry->hlist, hash);
return err;
}
+static int insert_ext_gid_entry(const char *key, appid_t value)
+{
+ int err;
+
+ mutex_lock(&sdcardfs_super_list_lock);
+ err = insert_ext_gid_entry_locked(key, value);
+ mutex_unlock(&sdcardfs_super_list_lock);
+
+ return err;
+}
+
static int insert_userid_exclude_entry(const char *key, userid_t value)
{
int err;
return err;
}
-static void free_packagelist_entry(struct hashtable_entry *entry)
+static void free_hashtable_entry(struct hashtable_entry *entry)
{
kfree(entry->key);
hash_del_rcu(&entry->dlist);
}
synchronize_rcu();
hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist)
- free_packagelist_entry(hash_cur);
+ free_hashtable_entry(hash_cur);
}
static void remove_packagelist_entry(const char *key)
return;
}
+static void remove_ext_gid_entry_locked(const char *key, gid_t group)
+{
+ struct hashtable_entry *hash_cur;
+ unsigned int hash = str_hash(key);
+
+ hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) {
+ if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == group) {
+ hash_del_rcu(&hash_cur->hlist);
+ synchronize_rcu();
+ free_hashtable_entry(hash_cur);
+ break;
+ }
+ }
+}
+
+static void remove_ext_gid_entry(const char *key, gid_t group)
+{
+ mutex_lock(&sdcardfs_super_list_lock);
+ remove_ext_gid_entry_locked(key, group);
+ mutex_unlock(&sdcardfs_super_list_lock);
+ return;
+}
+
static void remove_userid_all_entry_locked(userid_t userid)
{
struct hashtable_entry *hash_cur;
}
synchronize_rcu();
hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) {
- free_packagelist_entry(hash_cur);
+ free_hashtable_entry(hash_cur);
}
}
if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == userid) {
hash_del_rcu(&hash_cur->hlist);
synchronize_rcu();
- free_packagelist_entry(hash_cur);
+ free_hashtable_entry(hash_cur);
break;
}
}
}
synchronize_rcu();
hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist)
- free_packagelist_entry(hash_cur);
+ free_hashtable_entry(hash_cur);
mutex_unlock(&sdcardfs_super_list_lock);
printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n");
}
.ct_owner = THIS_MODULE,
};
+struct extensions_value {
+ struct config_group group;
+ unsigned int num;
+};
+
+struct extension_details {
+ struct config_item item;
+ const char *name;
+ unsigned int num;
+};
+
+static inline struct extensions_value *to_extensions_value(struct config_item *item)
+{
+ return item ? container_of(to_config_group(item), struct extensions_value, group) : NULL;
+}
+
+static inline struct extension_details *to_extension_details(struct config_item *item)
+{
+ return item ? container_of(item, struct extension_details, item) : NULL;
+}
+
+static void extension_details_release(struct config_item *item)
+{
+ struct extension_details *extension_details = to_extension_details(item);
+
+ printk(KERN_INFO "sdcardfs: No longer mapping %s files to gid %d\n",
+ extension_details->name, extension_details->num);
+ remove_ext_gid_entry(extension_details->name, extension_details->num);
+ kfree(extension_details->name);
+ kfree(extension_details);
+}
+
+static struct configfs_item_operations extension_details_item_ops = {
+ .release = extension_details_release,
+};
+
+static struct config_item_type extension_details_type = {
+ .ct_item_ops = &extension_details_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *extension_details_make_item(struct config_group *group, const char *name)
+{
+ struct extensions_value *extensions_value = to_extensions_value(&group->cg_item);
+ struct extension_details *extension_details = kzalloc(sizeof(struct extension_details), GFP_KERNEL);
+ int ret;
+ if (!extension_details)
+ return ERR_PTR(-ENOMEM);
+
+ extension_details->name = kstrdup(name, GFP_KERNEL);
+ if (!extension_details->name) {
+ kfree(extension_details);
+ return ERR_PTR(-ENOMEM);
+ }
+ extension_details->num = extensions_value->num;
+ ret = insert_ext_gid_entry(name, extensions_value->num);
+
+ if (ret) {
+ kfree(extension_details->name);
+ kfree(extension_details);
+ return ERR_PTR(ret);
+ }
+ config_item_init_type_name(&extension_details->item, name, &extension_details_type);
+
+ return &extension_details->item;
+}
+
+static struct configfs_group_operations extensions_value_group_ops = {
+ .make_item = extension_details_make_item,
+};
+
+static struct config_item_type extensions_name_type = {
+ .ct_group_ops = &extensions_value_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *extensions_make_group(struct config_group *group, const char *name)
+{
+ struct extensions_value *extensions_value;
+ unsigned int tmp;
+ int ret;
+
+ extensions_value = kzalloc(sizeof(struct extensions_value), GFP_KERNEL);
+ if (!extensions_value)
+ return ERR_PTR(-ENOMEM);
+ ret = kstrtouint(name, 10, &tmp);
+ if (ret) {
+ kfree(extensions_value);
+ return ERR_PTR(ret);
+ }
+
+ extensions_value->num = tmp;
+ config_group_init_type_name(&extensions_value->group, name,
+ &extensions_name_type);
+ return &extensions_value->group;
+}
+
+static void extensions_drop_group(struct config_group *group, struct config_item *item)
+{
+ struct extensions_value *value = to_extensions_value(item);
+ printk(KERN_INFO "sdcardfs: No longer mapping any files to gid %d\n", value->num);
+ kfree(value);
+}
+
+static struct configfs_group_operations extensions_group_ops = {
+ .make_group = extensions_make_group,
+ .drop_item = extensions_drop_group,
+};
+
+static struct config_item_type extensions_type = {
+ .ct_group_ops = &extensions_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+struct config_group extension_group = {
+ .cg_item = {
+ .ci_namebuf = "extensions",
+ .ci_type = &extensions_type,
+ },
+};
+
static struct config_item *packages_make_item(struct config_group *group, const char *name)
{
struct package_details *package_details;
.ct_owner = THIS_MODULE,
};
+struct config_group *sd_default_groups[] = {
+ &extension_group,
+ NULL,
+};
+
static struct configfs_subsystem sdcardfs_packages = {
.su_group = {
.cg_item = {
static int configfs_sdcardfs_init(void)
{
- int ret;
+ int ret, i;
struct configfs_subsystem *subsys = &sdcardfs_packages;
config_group_init(&subsys->su_group);
+ for (i = 0; sd_default_groups[i]; i++) {
+ config_group_init(sd_default_groups[i]);
+ configfs_add_default_group(sd_default_groups[i], &subsys->su_group);
+ }
mutex_init(&subsys->su_mutex);
ret = configfs_register_subsystem(subsys);
if (ret) {
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
+#define AID_MEDIA_OBB 1059 /* obb files */
+
+#define AID_SDCARD_IMAGE 1057
#define AID_PACKAGE_INFO 1027
* These two macro should be used in pair, and OVERRIDE_CRED() should be
* placed at the beginning of a function, right after variable declaration.
*/
-#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred) \
- saved_cred = override_fsids(sdcardfs_sbi); \
- if (!saved_cred) { return -ENOMEM; }
+#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \
+ do { \
+ saved_cred = override_fsids(sdcardfs_sbi, info); \
+ if (!saved_cred) \
+ return -ENOMEM; \
+ } while (0)
-#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred) \
- saved_cred = override_fsids(sdcardfs_sbi); \
- if (!saved_cred) { return ERR_PTR(-ENOMEM); }
+#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \
+ do { \
+ saved_cred = override_fsids(sdcardfs_sbi, info); \
+ if (!saved_cred) \
+ return ERR_PTR(-ENOMEM); \
+ } while (0)
#define REVERT_CRED(saved_cred) revert_fsids(saved_cred)
PERM_ANDROID_OBB,
/* This node is "/Android/media" */
PERM_ANDROID_MEDIA,
+ /* This node is "/Android/[data|media|obb]/[package]" */
+ PERM_ANDROID_PACKAGE,
+ /* This node is "/Android/[data|media|obb]/[package]/cache" */
+ PERM_ANDROID_PACKAGE_CACHE,
} perm_t;
struct sdcardfs_sb_info;
struct sdcardfs_mount_options;
+struct sdcardfs_inode_info;
/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
-const struct cred * override_fsids(struct sdcardfs_sb_info* sbi);
+const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_info *info);
/* Do not directly use this function, use REVERT_CRED() instead. */
void revert_fsids(const struct cred * old_cred);
userid_t userid;
uid_t d_uid;
bool under_android;
+ bool under_cache;
+ bool under_obb;
/* top folder for ownership */
struct inode *top;
/* for packagelist.c */
extern appid_t get_appid(const char *app_name);
+extern appid_t get_ext_gid(const char *app_name);
extern appid_t is_excluded(const char *app_name, userid_t userid);
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 setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
uid_t uid, bool under_android, struct inode *top);
extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
-extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry);
+extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const char *name);
+extern void drop_recursive(struct dentry *parent);
extern void fixup_top_recursive(struct dentry *parent);
extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit);
extern void update_derived_permission_lock(struct dentry *dentry);
+void fixup_lower_ownership(struct dentry *dentry, const char *name);
extern int need_graft_path(struct dentry *dentry);
extern int is_base_obbpath(struct dentry *dentry);
extern int is_obbpath_invalid(struct dentry *dentry);