Example #1
0
gid_t multiuser_get_ext_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_EXT_CACHE_GID_START);
    } else {
        return -1;
    }
}
void setup_derived_state_for_multiuser_gid(struct inode *inode, perm_t perm,
                        userid_t userid, uid_t uid, gid_t gid, bool under_android)
{
	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);

    setup_derived_state(inode, perm, userid, uid, gid, under_android);
	info->d_gid = multiuser_get_uid(userid, gid);
}
void get_derived_permission(struct dentry *parent, struct dentry *dentry)
{
	struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
	struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode);
	struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode);
	appid_t appid;

	/* By default, each inode inherits from its 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).
	 */

	inherit_derived_state(parent->d_inode, dentry->d_inode);

	/* 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(dentry->d_name.name, NULL, 10);
            if (sbi->options.sdfs_gid == AID_SDCARD_RW)
                info->d_gid = sbi->options.sdfs_gid;
            else
                info->d_gid = multiuser_get_uid(info->userid, sbi->options.sdfs_gid);
			break;
		case PERM_ROOT:
			/* Assume masked off by default. */
			if (!strcasecmp(dentry->d_name.name, "Android")) {
				/* App-specific directories inside; let anyone traverse */
				info->perm = PERM_ANDROID;
                info->d_under_android = true;
            }
			break;
		case PERM_ANDROID:
			if (!strcasecmp(dentry->d_name.name, "data")) {
				/* App-specific directories inside; let anyone traverse */
				info->perm = PERM_ANDROID_DATA;
			} else if (!strcasecmp(dentry->d_name.name, "obb")) {
				/* App-specific directories inside; let anyone traverse */
				info->perm = PERM_ANDROID_OBB;
				// FIXME : this feature will be implemented later.
				/* Single OBB directory is always shared */
                // ex. Fuse daemon..
                // node->graft_path = fuse->obb_path;
                // node->graft_pathlen = strlen(fuse->obb_path);
			} else if (!strcasecmp(dentry->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:
		case PERM_ANDROID_MEDIA:
			appid = get_appid(sbi->pkgl_id, dentry->d_name.name);
			if (appid != 0) {
				info->d_uid = multiuser_get_uid(parent_info->userid, appid);
			}
			break;
	}
}
Example #4
0
/*
 * our custom d_alloc_root work-alike
 *
 * we can't use d_alloc_root if we want to use our own interpose function
 * unchanged, so we simply call our own "fake" d_alloc_root
 */
static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb)
{
	struct dentry *ret = NULL;

	if (sb) {
		static const struct qstr name = {
			.name = "/",
			.len = 1
		};

		ret = __d_alloc(sb, &name);
		if (ret) {
			d_set_d_op(ret, &sdcardfs_ci_dops);
			ret->d_parent = ret;
		}
	}
	return ret;
}

/*
 * 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.
 */
static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
						void *raw_data, int silent)
{
	int err = 0;
	int debug;
	struct super_block *lower_sb;
	struct path lower_path;
	struct sdcardfs_sb_info *sb_info;
	void *pkgl_id;

	printk(KERN_INFO "sdcardfs version %s\n", SDCARDFS_VERSION);

	if (!dev_name) {
		printk(KERN_ERR
		       "sdcardfs: read_super: missing dev_name argument\n");
		err = -EINVAL;
		goto out;
	}

	printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name);
	printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data);

	/* parse lower path */
	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);
		goto out;
	}

	/* allocate superblock private data */
	sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL);
	if (!SDCARDFS_SB(sb)) {
		printk(KERN_CRIT "sdcardfs: read_super: out of memory\n");
		err = -ENOMEM;
		goto out_free;
	}

	sb_info = sb->s_fs_info;

	/* parse options */
	err = parse_options(sb, raw_data, silent, &debug, &sb_info->options);
	if (err) {
		printk(KERN_ERR	"sdcardfs: invalid options or out of memory\n");
		goto out_freesbi;
	}

    pkgl_id = packagelist_create((char *)dev_name);
    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);
	sdcardfs_set_lower_super(sb, lower_sb);

	/* inherit maxbytes from lower file system */
	sb->s_maxbytes = lower_sb->s_maxbytes;

	/*
	 * Our c/m/atime granularity is 1 ns because we may stack on file
	 * systems whose granularity is as good.
	 */
	sb->s_time_gran = 1;

	sb->s_magic = SDCARDFS_SUPER_MAGIC;
	sb->s_op = &sdcardfs_sops;

	/* see comment next to the definition of sdcardfs_d_alloc_root */
	sb->s_root = sdcardfs_d_alloc_root(sb);
	if (!sb->s_root) {
		err = -ENOMEM;
		goto out_sput;
	}

	/* link the upper and lower dentries */
	sb->s_root->d_fsdata = NULL;
	err = new_dentry_private_data(sb->s_root);
	if (err)
		goto out_freeroot;

	/* set the lower dentries for s_root */
	sdcardfs_set_lower_path(sb->s_root, &lower_path);

	/* call interpose to create the upper level inode */
	err = sdcardfs_interpose(sb->s_root, sb, &lower_path);
	if (!err) {
		/* setup permission policy */
        if (sb_info->options.multi_user)
        {
            setup_derived_state_for_multiuser_gid(sb->s_root->d_inode,
                    PERM_PRE_ROOT, 0, AID_ROOT, multiuser_get_uid(0,sb_info->options.sdfs_gid), false);
            sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
				snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
        }
        else
        {
            setup_derived_state(sb->s_root->d_inode,
                    PERM_ROOT, 0, AID_ROOT, multiuser_get_uid(0, sb_info->options.sdfs_gid), false);
            sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
				snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
        }
        fix_derived_permission(sb->s_root->d_inode, sb_info->options.sdfs_mask);

		if (!silent)
			printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n",
						dev_name, lower_sb->s_type->name);
		goto out;
	}
	/* else error: fall through */

	free_dentry_private_data(sb->s_root);
out_freeroot:
	dput(sb->s_root);
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;
out_free:
	path_put(&lower_path);

out:
	return err;
}
Example #5
0
static int initialize_directories() {
    int res = -1;

    // Read current filesystem layout version to handle upgrade paths
    char version_path[PATH_MAX];
    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());

    int oldVersion;
    if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
        oldVersion = 0;
    }
    int version = oldVersion;

    if (version < 2) {
        SLOGD("Assuming that device has multi-user storage layout; upgrade no longer supported");
        version = 2;
    }

    if (ensure_config_user_dirs(0) == -1) {
        SLOGE("Failed to setup misc for user 0");
        goto fail;
    }

    if (version == 2) {
        SLOGD("Upgrading to /data/misc/user directories");

        char misc_dir[PATH_MAX];
        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());

        char keychain_added_dir[PATH_MAX];
        snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);

        char keychain_removed_dir[PATH_MAX];
        snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir);

        DIR *dir;
        struct dirent *dirent;
        dir = opendir("/data/user");
        if (dir != NULL) {
            while ((dirent = readdir(dir))) {
                const char *name = dirent->d_name;

                // skip "." and ".."
                if (name[0] == '.') {
                    if (name[1] == 0) continue;
                    if ((name[1] == '.') && (name[2] == 0)) continue;
                }

                uint32_t user_id = std::stoi(name);

                // /data/misc/user/<user_id>
                if (ensure_config_user_dirs(user_id) == -1) {
                    goto fail;
                }

                char misc_added_dir[PATH_MAX];
                snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name);

                char misc_removed_dir[PATH_MAX];
                snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name);

                uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM);
                gid_t gid = uid;
                if (access(keychain_added_dir, F_OK) == 0) {
                    if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) {
                        SLOGE("Some files failed to copy");
                    }
                }
                if (access(keychain_removed_dir, F_OK) == 0) {
                    if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) {
                        SLOGE("Some files failed to copy");
                    }
                }
            }
            closedir(dir);

            if (access(keychain_added_dir, F_OK) == 0) {
                delete_dir_contents(keychain_added_dir, 1, 0);
            }
            if (access(keychain_removed_dir, F_OK) == 0) {
                delete_dir_contents(keychain_removed_dir, 1, 0);
            }
        }

        version = 3;
    }

    // Persist layout version if changed
    if (version != oldVersion) {
        if (fs_write_atomic_int(version_path, version) == -1) {
            SLOGE("Failed to save version to %s: %s", version_path, strerror(errno));
            goto fail;
        }
    }

    // Success!
    res = 0;

fail:
    return res;
}
void get_derived_permission_lollipop(struct dentry *parent, struct dentry *dentry)
{
	struct sdcardfslp_sb_info *sbi = SDCARDFSLP_SB(dentry->d_sb);
	struct sdcardfslp_inode_info *info = SDCARDFSLP_I(dentry->d_inode);
	struct sdcardfslp_inode_info *parent_info= SDCARDFSLP_I(parent->d_inode);
	appid_t appid;

	/* By default, each inode inherits from its 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).
	 */

	inherit_derived_state(parent->d_inode, dentry->d_inode);

	//printk(KERN_INFO "sdcardfslp: 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:
			/* Legacy internal layout places users at top level */
			info->perm = PERM_ROOT;
			info->userid = simple_strtoul(dentry->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")) {
				/* 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;
				}
			}
			break;
		case PERM_ANDROID:
			if (!strcasecmp(dentry->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")) {
				/* 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, "media")) {
				/* App-specific directories inside; let anyone traverse */
				info->perm = PERM_ANDROID_MEDIA;
				info->d_mode = 00771;
			} 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;
			}
			break;
		/* same policy will be applied on PERM_ANDROID_DATA
		 * and PERM_ANDROID_OBB */
		case PERM_ANDROID_DATA:
		case PERM_ANDROID_OBB:
		case PERM_ANDROID_MEDIA:
			appid = get_appid_lollipop(sbi->pkgl_id, dentry->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;
	}
}