Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6356fc2f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "PFK: fix race between key set and key invalidate in TZ"

parents d67a03f5 51919530
Loading
Loading
Loading
Loading
+45 −28
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -97,19 +97,16 @@ struct ice_device {
static int qti_ice_setting_config(struct request *req,
		struct platform_device *pdev,
		struct ice_crypto_setting *crypto_data,
		struct ice_data_setting *setting,
		bool *configured)
		struct ice_data_setting *setting)
{
	struct ice_device *ice_dev = NULL;

	*configured = false;
	ice_dev = platform_get_drvdata(pdev);

	if (!ice_dev) {
		pr_debug("%s no ICE device\n", __func__);

		/* make the caller finish peacfully */
		*configured = true;
		return 0;
	}

@@ -120,8 +117,6 @@ static int qti_ice_setting_config(struct request *req,

	if ((short)(crypto_data->key_index) >= 0) {

		*configured = true;

		memcpy(&setting->crypto_data, crypto_data,
				sizeof(setting->crypto_data));

@@ -1375,7 +1370,7 @@ static int qcom_ice_config(struct platform_device *pdev, struct request *req,
	struct ice_crypto_setting pfk_crypto_data = {0};
	union map_info *info;
	int ret = 0;
	bool configured = 0;
	bool is_pfe = false;

	if (!pdev || !req || !setting) {
		pr_err("%s: Invalid params passed\n", __func__);
@@ -1397,25 +1392,17 @@ static int qcom_ice_config(struct platform_device *pdev, struct request *req,
		return 0;
	}

	ret = pfk_load_key(req->bio, &pfk_crypto_data);
	if (0 == ret) {
		ret = qti_ice_setting_config(req, pdev, &pfk_crypto_data,
			setting, &configured);

		if (0 == ret) {
			/**
			 * if configuration was complete, we are done, no need
			 * to go further with FDE
			 */
			if (configured)
				return 0;
		} else {
			/**
			 * there was an error with configuring the setting,
			 * exit with error
			 */
	ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, false);
	if (is_pfe) {
		if (ret) {
			if (ret != -EBUSY && ret != -EAGAIN)
				pr_err("%s error %d while configuring ice key for PFE\n",
						__func__, ret);
			return ret;
		}

		return qti_ice_setting_config(req, pdev,
				&pfk_crypto_data, setting);
	}

	/*
@@ -1438,8 +1425,8 @@ static int qcom_ice_config(struct platform_device *pdev, struct request *req,
			return -EINVAL;
		}

		return qti_ice_setting_config(req, pdev, crypto_data,
			setting, &configured);
		return qti_ice_setting_config(req, pdev,
				crypto_data, setting);
	}

	/*
@@ -1450,6 +1437,35 @@ static int qcom_ice_config(struct platform_device *pdev, struct request *req,
	return 0;
}

static int qcom_ice_config_end(struct request *req)
{
	int ret = 0;
	bool is_pfe = false;

	if (!req) {
		pr_err("%s: Invalid params passed\n", __func__);
		return -EINVAL;
	}

	if (!req->bio) {
		/* It is not an error to have a request with no  bio */
		return 0;
	}

	ret = pfk_load_key_end(req->bio, &is_pfe);
	if (is_pfe) {
		if (ret != 0)
			pr_err("%s error %d while end configuring ice key for PFE\n",
								__func__, ret);
		return ret;
	}


	return 0;
}
EXPORT_SYMBOL(qcom_ice_config_end);


static int qcom_ice_status(struct platform_device *pdev)
{
	struct ice_device *ice_dev;
@@ -1482,6 +1498,7 @@ struct qcom_ice_variant_ops qcom_ice_ops = {
	.resume           = qcom_ice_resume,
	.suspend          = qcom_ice_suspend,
	.config		  = qcom_ice_config,
	.config_end       = qcom_ice_config_end,
	.status           = qcom_ice_status,
	.debug            = qcom_ice_debug,
};
+30 −0
Original line number Diff line number Diff line
@@ -366,6 +366,36 @@ out:
	return err;
}

/**
 * ufs_qcom_ice_cfg_end() - finishes configuring UFS's ICE registers
 *							for an ICE transaction
 * @qcom_host:	Pointer to a UFS QCom internal host structure.
 *				qcom_host, qcom_host->hba and
 *				qcom_host->hba->dev should all
 *				be valid pointers.
 * @cmd:	Pointer to a valid scsi command. cmd->request should also be
 *              a valid pointer.
 *
 * Return: -EINVAL in-case of an error
 *         0 otherwise
 */
int ufs_qcom_ice_cfg_end(struct ufs_qcom_host *qcom_host, struct request *req)
{
	int err = 0;
	struct device *dev = qcom_host->hba->dev;

	if (qcom_host->ice.vops->config_end) {
		err = qcom_host->ice.vops->config_end(req);
		if (err) {
			dev_err(dev, "%s: error in ice_vops->config_end %d\n",
				__func__, err);
			return err;
		}
	}

	return 0;
}

/**
 * ufs_qcom_ice_reset() - resets UFS-ICE interface and ICE device
 * @qcom_host:	Pointer to a UFS QCom internal host structure.
+4 −3
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -71,6 +71,7 @@ struct qcom_ice_variant_ops {
	int	(*suspend)(struct platform_device *);
	int	(*config)(struct platform_device *, struct request *,
				struct ice_data_setting *);
	int	(*config_end)(struct request *);
	int	(*status)(struct platform_device *);
	void	(*debug)(struct platform_device *);
};
+11 −4
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -19,13 +19,20 @@ struct ice_crypto_setting;

#ifdef CONFIG_PFK

int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting);
int pfk_load_key_start(const struct bio *bio,
		struct ice_crypto_setting *ice_setting, bool *is_pfe, bool);
int pfk_load_key_end(const struct bio *bio, bool *is_pfe);
int pfk_remove_key(const unsigned char *key, size_t key_size);
bool pfk_allow_merge_bio(struct bio *bio1, struct bio *bio2);

#else
static inline int pfk_load_key(const struct bio *bio,
		struct ice_crypto_setting *ice_setting)
static inline int pfk_load_key_start(const struct bio *bio,
	struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async)
{
	return -ENODEV;
}

static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
{
	return -ENODEV;
}
+160 −63
Original line number Diff line number Diff line
@@ -174,7 +174,7 @@ static inline bool pfk_is_ready(void)
static int pfk_get_page_index(const struct bio *bio, pgoff_t *page_index)
{
	if (!bio || !page_index)
		return -EPERM;
		return -EINVAL;

	if (!bio_has_data((struct bio *)bio))
		return -EINVAL;
@@ -271,7 +271,7 @@ static int pfk_set_ecryptfs_data(struct inode *inode, void *ecryptfs_data)
	struct inode_security_struct *isec = NULL;

	if (!inode)
		return -EPERM;
		return -EINVAL;

	isec = inode->i_security;

@@ -344,54 +344,39 @@ static int pfk_key_size_to_key_type(size_t key_size,
	return 0;
}

/**
 * pfk_load_key() - loads the encryption key to the ICE
 * @bio: Pointer to the BIO structure
 * @ice_setting: Pointer to ice setting structure that will be filled with
 * ice configuration values, including the index to which the key was loaded
 *
 * Via bio gets access to ecryptfs key stored in auxiliary structure inside
 * inode and loads it to encryption hw.
 * Returns the index where the key is stored in encryption hw and additional
 * information that will be used later for configuration of the encryption hw.
 *
 */
int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
static int pfk_bio_to_key(const struct bio *bio, unsigned char const **key,
		size_t *key_size, unsigned char const **salt, size_t *salt_size,
		bool *is_pfe)
{
	struct inode *inode = NULL;
	int ret = 0;
	const unsigned char *key = NULL;
	const unsigned char *salt = NULL;
	const unsigned char *cipher = NULL;
	void *ecryptfs_data = NULL;
	u32 key_index = 0;
	enum ice_cryto_algo_mode algo_mode = 0;
	enum ice_crpto_key_size key_size_type = 0;
	size_t key_size = 0;
	size_t salt_size = 0;
	pgoff_t offset;
	bool is_metadata = false;

	if (!pfk_is_ready())
		return -ENODEV;
	/* only a few errors below can indicate that
	 * this function was not invoked within PFE context,
	 * otherwise we will consider it PFE
	 */
	*is_pfe = true;


	if (!bio)
		return -EPERM;
		return -EINVAL;

	if (!ice_setting) {
		pr_err("ice setting is NULL\n");
		return -EPERM;
	}
	if (!key || !salt || !key_size || !salt_size)
		return -EINVAL;

	inode = pfk_bio_get_inode(bio);
	if (!inode)
	if (!inode) {
		*is_pfe = false;
		return -EINVAL;
	}

	ecryptfs_data = pfk_get_ecryptfs_data(inode);

	if (!ecryptfs_data) {
		ret = -EINVAL;
		goto end;
		*is_pfe = false;
		return -EPERM;
	}

	pr_debug("loading key for file %s\n", inode_to_filename(inode));
@@ -400,48 +385,116 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
	if (ret != 0) {
		pr_err("could not get page index from bio, probably bug %d\n",
				ret);
		ret = -EINVAL;
		goto end;
		return -EINVAL;
	}

	is_metadata = ecryptfs_is_page_in_metadata(ecryptfs_data, offset);
	if (is_metadata == true) {
		pr_debug("ecryptfs metadata, bypassing ICE\n");
		ret = -ESPIPE;
		goto end;
		*is_pfe = false;
		return -EPERM;
	}

	key = ecryptfs_get_key(ecryptfs_data);
	*key = ecryptfs_get_key(ecryptfs_data);
	if (!key) {
		pr_err("could not parse key from ecryptfs\n");
		ret = -EINVAL;
		goto end;
		return -EINVAL;
	}

	key_size = ecryptfs_get_key_size(ecryptfs_data);
	if (!key_size) {
	*key_size = ecryptfs_get_key_size(ecryptfs_data);
	if (!(*key_size)) {
		pr_err("could not parse key size from ecryptfs\n");
		ret = -EINVAL;
		goto end;
		return -EINVAL;
	}

	salt = ecryptfs_get_salt(ecryptfs_data);
	*salt = ecryptfs_get_salt(ecryptfs_data);
	if (!salt) {
		pr_err("could not parse salt from ecryptfs\n");
		ret = -EINVAL;
		goto end;
		return -EINVAL;
	}

	salt_size = ecryptfs_get_salt_size(ecryptfs_data);
	if (!salt_size) {
	*salt_size = ecryptfs_get_salt_size(ecryptfs_data);
	if (!(*salt_size)) {
		pr_err("could not parse salt size from ecryptfs\n");
		ret = -EINVAL;
		goto end;
		return -EINVAL;
	}

	ret = pfk_parse_cipher(cipher, &algo_mode);
	return 0;
}

/**
 * pfk_load_key_start() - loads PFE encryption key to the ICE
 *						  Can also be invoked from non
 *						  PFE context, than it is not
 *						  relevant and is_pfe flag is
 *						  set to true
 * @bio: Pointer to the BIO structure
 * @ice_setting: Pointer to ice setting structure that will be filled with
 * ice configuration values, including the index to which the key was loaded
 * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked
 *			from PFE context
 *
 * Via bio gets access to ecryptfs key stored in auxiliary structure inside
 * inode and loads it to encryption hw.
 * Returns the index where the key is stored in encryption hw and additional
 * information that will be used later for configuration of the encryption hw.
 *
 * Must be followed by pfk_load_key_end when key is no longer used by ice
 *
 */
int pfk_load_key_start(const struct bio *bio,
		struct ice_crypto_setting *ice_setting, bool *is_pfe,
		bool async)
{
	int ret = 0;
	const unsigned char *key = NULL;
	const unsigned char *salt = NULL;
	size_t key_size = 0;
	size_t salt_size = 0;
	enum ice_cryto_algo_mode algo_mode = 0;
	enum ice_crpto_key_size key_size_type = 0;
	void *ecryptfs_data = NULL;
	u32 key_index = 0;
	struct inode *inode = NULL;

	if (!is_pfe) {
		pr_err("is_pfe is NULL\n");
		return -EINVAL;
	}

	/* only a few errors below can indicate that
	 * this function was not invoked within PFE context,
	 * otherwise we will consider it PFE
	 */
	*is_pfe = true;

	if (!pfk_is_ready())
		return -ENODEV;

	if (!ice_setting) {
		pr_err("ice setting is NULL\n");
		return -EINVAL;
	}

	ret = pfk_bio_to_key(bio, &key, &key_size, &salt, &salt_size, is_pfe);
	if (ret != 0)
		return ret;

	inode = pfk_bio_get_inode(bio);
	if (!inode) {
		*is_pfe = false;
		return -EINVAL;
	}

	ecryptfs_data = pfk_get_ecryptfs_data(inode);
	if (!ecryptfs_data) {
		*is_pfe = false;
		return -EPERM;
	}

	ret = pfk_parse_cipher(ecryptfs_data, &algo_mode);
	if (ret != 0) {
		pr_debug("not supported cipher\n");
		pr_err("not supported cipher\n");
		return ret;
	}

@@ -449,11 +502,14 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
	if (ret != 0)
		return ret;

	ret = pfk_kc_load_key(key, key_size, salt, salt_size, &key_index);
	if (ret != 0) {
		pr_err("could not load key into pfk key cache, error %d\n",
	ret = pfk_kc_load_key_start(key, key_size, salt, salt_size, &key_index,
			async);
	if (ret) {
		if (ret != -EBUSY && ret != -EAGAIN)
			pr_err("start: could not load key into pfk key cache, error %d\n",
					ret);
		return -EINVAL;

		return ret;
	}

	ice_setting->key_size = key_size_type;
@@ -463,10 +519,51 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
	ice_setting->key_index = key_index;

	return 0;
}

end:
/**
 * pfk_load_key_end() - marks the PFE key as no longer used by ICE
 *						Can also be invoked from non
 *						PFE context, than it is not
 *						relevant and is_pfe flag is
 *						set to true
 * @bio: Pointer to the BIO structure
 * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked
 *			from PFE context
 *
 * Via bio gets access to ecryptfs key stored in auxiliary structure inside
 * inode and loads it to encryption hw.
 *
 */
int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
{
	int ret = 0;
	const unsigned char *key = NULL;
	const unsigned char *salt = NULL;
	size_t key_size = 0;
	size_t salt_size = 0;

	if (!is_pfe) {
		pr_err("is_pfe is NULL\n");
		return -EINVAL;
	}

	/* only a few errors below can indicate that
	 * this function was not invoked within PFE context,
	 * otherwise we will consider it PFE
	 */
	*is_pfe = true;

	if (!pfk_is_ready())
		return -ENODEV;

	ret = pfk_bio_to_key(bio, &key, &key_size, &salt, &salt_size, is_pfe);
	if (ret != 0)
		return ret;

	pfk_kc_load_key_end(key, key_size, salt, salt_size);

	return 0;
}

/**
@@ -488,7 +585,7 @@ int pfk_remove_key(const unsigned char *key, size_t key_size)
		return -ENODEV;

	if (!key)
		return -EPERM;
		return -EINVAL;

	ret = pfk_kc_remove_key(key, key_size);

Loading