ANDROID: sdcardfs: Switch strcasecmp for internal call

This moves our uses of strcasecmp over to an internal call so we can
easily change implementations later if we so desire. Additionally,
we leverage qstr's where appropriate to save time on comparisons.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
Change-Id: I32fdc4fd0cd3b7b735dcfd82f60a2516fd8272a5
This commit is contained in:
Daniel Rosenberg 2017-01-31 20:07:51 -08:00 committed by Amit Pundir
parent 4bc036fa91
commit f36083a078
6 changed files with 79 additions and 58 deletions

View file

@ -51,11 +51,16 @@ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
}
/* 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, const char *name)
void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
struct sdcardfs_inode_info *parent_info= SDCARDFS_I(d_inode(parent));
appid_t appid;
struct qstr q_Android = QSTR_LITERAL("Android");
struct qstr q_data = QSTR_LITERAL("data");
struct qstr q_obb = QSTR_LITERAL("obb");
struct qstr q_media = QSTR_LITERAL("media");
struct qstr q_cache = QSTR_LITERAL("cache");
/* By default, each inode inherits from its parent.
* the properties are maintained on its private fields
@ -79,12 +84,12 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co
case PERM_PRE_ROOT:
/* Legacy internal layout places users at top level */
info->perm = PERM_ROOT;
info->userid = simple_strtoul(name, NULL, 10);
info->userid = simple_strtoul(name->name, NULL, 10);
set_top(info, &info->vfs_inode);
break;
case PERM_ROOT:
/* Assume masked off by default. */
if (!strcasecmp(name, "Android")) {
if (qstr_case_eq(name, &q_Android)) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID;
info->under_android = true;
@ -92,17 +97,17 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co
}
break;
case PERM_ANDROID:
if (!strcasecmp(name, "data")) {
if (qstr_case_eq(name, &q_data)) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_DATA;
set_top(info, &info->vfs_inode);
} else if (!strcasecmp(name, "obb")) {
} else if (qstr_case_eq(name, &q_obb)) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_OBB;
info->under_obb = true;
set_top(info, &info->vfs_inode);
/* Single OBB directory is always shared */
} else if (!strcasecmp(name, "media")) {
} else if (qstr_case_eq(name, &q_media)) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_MEDIA;
set_top(info, &info->vfs_inode);
@ -112,14 +117,14 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co
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)) {
appid = get_appid(name->name);
if (appid != 0 && !is_excluded(name->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")) {
if (qstr_case_eq(name, &q_cache)) {
info->perm = PERM_ANDROID_PACKAGE_CACHE;
info->under_cache = true;
}
@ -129,7 +134,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co
void get_derived_permission(struct dentry *parent, struct dentry *dentry)
{
get_derived_permission_new(parent, dentry, dentry->d_name.name);
get_derived_permission_new(parent, dentry, &dentry->d_name);
}
static appid_t get_type(const char *name)
@ -366,9 +371,10 @@ int need_graft_path(struct dentry *dentry)
struct dentry *parent = dget_parent(dentry);
struct sdcardfs_inode_info *parent_info= SDCARDFS_I(d_inode(parent));
struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
struct qstr obb = QSTR_LITERAL("obb");
if(parent_info->perm == PERM_ANDROID &&
!strcasecmp(dentry->d_name.name, "obb")) {
qstr_case_eq(&dentry->d_name, &obb)) {
/* /Android/obb is the base obbpath of DERIVED_UNIFIED */
if(!(sbi->options.multiuser == false
@ -405,7 +411,7 @@ int is_obbpath_invalid(struct dentry *dent)
} else {
obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX);
if (d_unhashed(di->lower_path.dentry) ||
strcasecmp(sbi->obbpath_s, obbpath_s)) {
!str_case_eq(sbi->obbpath_s, obbpath_s)) {
ret = 1;
}
kfree(path_buf);
@ -425,15 +431,16 @@ int is_base_obbpath(struct dentry *dentry)
struct dentry *parent = dget_parent(dentry);
struct sdcardfs_inode_info *parent_info= SDCARDFS_I(d_inode(parent));
struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
struct qstr q_obb = QSTR_LITERAL("obb");
spin_lock(&SDCARDFS_D(dentry)->lock);
if (sbi->options.multiuser) {
if(parent_info->perm == PERM_PRE_ROOT &&
!strcasecmp(dentry->d_name.name, "obb")) {
qstr_case_eq(&dentry->d_name, &q_obb)) {
ret = 1;
}
} else if (parent_info->perm == PERM_ANDROID &&
!strcasecmp(dentry->d_name.name, "obb")) {
qstr_case_eq(&dentry->d_name, &q_obb)) {
ret = 1;
}
spin_unlock(&SDCARDFS_D(dentry)->lock);

View file

@ -216,7 +216,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file)
goto out_err;
}
if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
if (!check_caller_access_to_name(d_inode(parent), &dentry->d_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);

View file

@ -66,7 +66,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry,
struct fs_struct *saved_fs;
struct fs_struct *copied_fs;
if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
if (!check_caller_access_to_name(dir, &dentry->d_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);
@ -168,7 +168,7 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry)
struct path lower_path;
const struct cred *saved_cred = NULL;
if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
if (!check_caller_access_to_name(dir, &dentry->d_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);
@ -275,8 +275,10 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
int touch_err = 0;
struct fs_struct *saved_fs;
struct fs_struct *copied_fs;
struct qstr q_obb = QSTR_LITERAL("obb");
struct qstr q_data = QSTR_LITERAL("data");
if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
if (!check_caller_access_to_name(dir, &dentry->d_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);
@ -351,13 +353,13 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
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"))
if ((!sbi->options.multiuser) && (qstr_case_eq(&dentry->d_name, &q_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")))) {
((pi->perm == PERM_ANDROID) && (qstr_case_eq(&dentry->d_name, &q_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);
@ -388,7 +390,7 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry)
struct path lower_path;
const struct cred *saved_cred = NULL;
if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
if (!check_caller_access_to_name(dir, &dentry->d_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);
@ -480,8 +482,8 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (flags)
return -EINVAL;
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)) {
if (!check_caller_access_to_name(old_dir, &old_dentry->d_name) ||
!check_caller_access_to_name(new_dir, &new_dentry->d_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);
@ -527,7 +529,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_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));
}
get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry->d_name.name);
get_derived_permission_new(new_dentry->d_parent, old_dentry, &new_dentry->d_name);
fixup_tmp_permissions(d_inode(old_dentry));
fixup_lower_ownership(old_dentry, new_dentry->d_name.name);
drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */
@ -752,7 +754,7 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct
if (!err) {
/* check the Android group ID */
parent = dget_parent(dentry);
if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
if (!check_caller_access_to_name(d_inode(parent), &dentry->d_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);
@ -870,7 +872,7 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
int err;
parent = dget_parent(dentry);
if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
if (!check_caller_access_to_name(d_inode(parent), &dentry->d_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);

View file

@ -219,9 +219,8 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
struct vfsmount *lower_dir_mnt;
struct dentry *lower_dir_dentry = NULL;
struct dentry *lower_dentry;
const char *name;
const struct qstr *name;
struct path lower_path;
struct qstr this;
struct sdcardfs_sb_info *sbi;
sbi = SDCARDFS_SB(dentry->d_sb);
@ -231,14 +230,14 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
if (IS_ROOT(dentry))
goto out;
name = dentry->d_name.name;
name = &dentry->d_name;
/* now start the actual lookup procedure */
lower_dir_dentry = lower_parent_path->dentry;
lower_dir_mnt = lower_parent_path->mnt;
/* Use vfs_path_lookup to check if the dentry exists or not */
err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0,
err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name->name, 0,
&lower_path);
/* check for other cases */
if (err == -ENOENT) {
@ -248,7 +247,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
spin_lock(&lower_dir_dentry->d_lock);
list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_child) {
if (child && d_inode(child)) {
if (strcasecmp(child->d_name.name, name)==0) {
if (qstr_case_eq(&child->d_name, name)) {
match = dget(child);
break;
}
@ -307,14 +306,11 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
goto out;
/* instatiate a new negative dentry */
this.name = name;
this.len = strlen(name);
this.hash = full_name_hash(dentry, this.name, this.len);
lower_dentry = d_lookup(lower_dir_dentry, &this);
lower_dentry = d_lookup(lower_dir_dentry, name);
if (lower_dentry)
goto setup_lower;
lower_dentry = d_alloc(lower_dir_dentry, &this);
lower_dentry = d_alloc(lower_dir_dentry, name);
if (!lower_dentry) {
err = -ENOMEM;
goto out;
@ -359,7 +355,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
parent = dget_parent(dentry);
if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
if (!check_caller_access_to_name(d_inode(parent), &dentry->d_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",

View file

@ -67,7 +67,7 @@ static appid_t __get_appid(const struct qstr *key)
rcu_read_lock();
hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name)) {
if (qstr_case_eq(key, &hash_cur->key)) {
ret_id = atomic_read(&hash_cur->value);
rcu_read_unlock();
return ret_id;
@ -92,7 +92,7 @@ static appid_t __get_ext_gid(const struct qstr *key)
rcu_read_lock();
hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name)) {
if (qstr_case_eq(key, &hash_cur->key)) {
ret_id = atomic_read(&hash_cur->value);
rcu_read_unlock();
return ret_id;
@ -117,7 +117,7 @@ static appid_t __is_excluded(const struct qstr *app_name, userid_t user)
rcu_read_lock();
hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) {
if (atomic_read(&hash_cur->value) == user &&
!strcasecmp(app_name->name, hash_cur->key.name)) {
qstr_case_eq(app_name, &hash_cur->key)) {
rcu_read_unlock();
return 1;
}
@ -126,24 +126,27 @@ static appid_t __is_excluded(const struct qstr *app_name, userid_t user)
return 0;
}
appid_t is_excluded(const char *app_name, userid_t user)
appid_t is_excluded(const char *key, userid_t user)
{
struct qstr q;
qstr_init(&q, app_name);
qstr_init(&q, key);
return __is_excluded(&q, user);
}
/* 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 struct qstr *name)
{
struct qstr q_autorun = QSTR_LITERAL("autorun.inf");
struct qstr q__android_secure = QSTR_LITERAL(".android_secure");
struct qstr q_android_secure = QSTR_LITERAL("android_secure");
/* Always block security-sensitive files at root */
if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) {
if (!strcasecmp(name, "autorun.inf")
|| !strcasecmp(name, ".android_secure")
|| !strcasecmp(name, "android_secure")) {
if (qstr_case_eq(name, &q_autorun)
|| qstr_case_eq(name, &q__android_secure)
|| qstr_case_eq(name, &q_android_secure)) {
return 0;
}
}
@ -195,7 +198,7 @@ static int insert_packagelist_appid_entry_locked(const struct qstr *key, appid_t
unsigned int hash = key->hash;
hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name)) {
if (qstr_case_eq(key, &hash_cur->key)) {
atomic_set(&hash_cur->value, value);
return 0;
}
@ -215,7 +218,7 @@ static int insert_ext_gid_entry_locked(const struct qstr *key, appid_t value)
/* An extension can only belong to one gid */
hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name))
if (qstr_case_eq(key, &hash_cur->key))
return -EINVAL;
}
new_entry = alloc_hashtable_entry(key, value);
@ -234,7 +237,7 @@ static int insert_userid_exclude_entry_locked(const struct qstr *key, userid_t v
/* Only insert if not already present */
hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) {
if (atomic_read(&hash_cur->value) == value &&
!strcasecmp(key->name, hash_cur->key.name))
qstr_case_eq(key, &hash_cur->key))
return 0;
}
new_entry = alloc_hashtable_entry(key, value);
@ -338,13 +341,13 @@ static void remove_packagelist_entry_locked(const struct qstr *key)
HLIST_HEAD(free_list);
hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name)) {
if (qstr_case_eq(key, &hash_cur->key)) {
hash_del_rcu(&hash_cur->hlist);
hlist_add_head(&hash_cur->dlist, &free_list);
}
}
hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name)) {
if (qstr_case_eq(key, &hash_cur->key)) {
hash_del_rcu(&hash_cur->hlist);
hlist_add_head(&hash_cur->dlist, &free_list);
break;
@ -370,7 +373,7 @@ static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group)
unsigned int hash = key->hash;
hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name) && atomic_read(&hash_cur->value) == group) {
if (qstr_case_eq(key, &hash_cur->key) && atomic_read(&hash_cur->value) == group) {
hash_del_rcu(&hash_cur->hlist);
synchronize_rcu();
free_hashtable_entry(hash_cur);
@ -421,7 +424,7 @@ static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t
unsigned int hash = key->hash;
hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) {
if (!strcasecmp(key->name, hash_cur->key.name) &&
if (qstr_case_eq(key, &hash_cur->key) &&
atomic_read(&hash_cur->value) == userid) {
hash_del_rcu(&hash_cur->hlist);
synchronize_rcu();
@ -530,7 +533,7 @@ static ssize_t package_details_excluded_userids_show(struct config_item *item,
rcu_read_lock();
hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) {
if (!strcasecmp(package_details->name.name, hash_cur->key.name))
if (qstr_case_eq(&package_details->name, &hash_cur->key))
count += scnprintf(page + count, PAGE_SIZE - count,
"%d ", atomic_read(&hash_cur->value));
}
@ -759,7 +762,7 @@ static ssize_t packages_list_show(struct config_item *item, char *page)
hash_cur_app->key.name, atomic_read(&hash_cur_app->value));
hash = hash_cur_app->key.hash;
hash_for_each_possible_rcu(package_to_userid, hash_cur_user, hlist, hash) {
if (!strcasecmp(hash_cur_app->key.name, hash_cur_user->key.name)) {
if (qstr_case_eq(&hash_cur_app->key, &hash_cur_user->key)) {
written += scnprintf(page + count + written - 1,
PAGE_SIZE - sizeof(errormsg) - count - written + 1,
" %d\n", atomic_read(&hash_cur_user->value)) - 1;

View file

@ -465,7 +465,7 @@ extern struct list_head sdcardfs_super_list;
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 check_caller_access_to_name(struct inode *parent_node, const struct qstr *name);
extern int open_flags_to_access_mode(int open_flags);
extern int packagelist_init(void);
extern void packagelist_exit(void);
@ -483,7 +483,7 @@ struct limit_search {
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, const char *name);
extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *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);
@ -611,4 +611,17 @@ static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct
dest->i_flags = src->i_flags;
set_nlink(dest, src->i_nlink);
}
static inline bool str_case_eq(const char *s1, const char *s2)
{
return !strcasecmp(s1, s2);
}
static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2)
{
return q1->len == q2->len && str_case_eq(q1->name, q2->name);
}
#define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1)
#endif /* not _SDCARDFS_H_ */