/* Encode the parameters and type of an operation from the TEE API format
   into an SChannel message. */
void TEEC_encode_parameters(u16 *param_types,
			    union tf_command_param *params,
			    TEEC_Operation *operation)
{
	unsigned i;
	if (operation == NULL) {
		*param_types = 0;
		return;
	}
	*param_types = operation->paramTypes;
	for (i = 0; i < 4; i++) {
		unsigned ty = TF_GET_PARAM_TYPE(operation->paramTypes, i);
		TEEC_Parameter *op = operation->params + i;
		if (ty & TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG) {
			TEEC_SharedMemory *sm = op->memref.parent;
			params[i].memref.block = sm->imp._block;
			if (ty == TEEC_MEMREF_WHOLE) {
				TEEC_encode_whole_memref_flags(param_types, i,
							       sm->flags);
				params[i].memref.size = sm->size;
				params[i].memref.offset = 0;
			} else {
				params[i].memref.size = op->memref.size;
				params[i].memref.offset = op->memref.offset;
			}
		} else if (ty & TF_PARAM_TYPE_MEMREF_FLAG) {
			/* Set up what tf_map_temp_shmem (called by
			   tf_open_client_session and
			   tf_invoke_client_command) expects:
			   .descriptor and .offset to both be set to the
			   address of the buffer. */
			u32 address = (u32)op->tmpref.buffer;
			params[i].temp_memref.descriptor = address;
			params[i].temp_memref.size = op->tmpref.size;
			params[i].temp_memref.offset = address;
		} else if (ty & TF_PARAM_TYPE_INPUT_FLAG) {
			params[i].value.a = op->value.a;
			params[i].value.b = op->value.b;
		} else {
			/* output-only value or none, so nothing to do */
		}
	}
}
/* Decode updated parameters from an SChannel answer into the TEE API format. */
void TEEC_decode_parameters(union tf_answer_param *params,
			    TEEC_Operation *operation)
{
	unsigned i;
	if (operation == NULL) {
		return;
	}
	for (i = 0; i < 4; i++) {
		unsigned ty = TF_GET_PARAM_TYPE(operation->paramTypes, i);
		TEEC_Parameter *op = operation->params + i;
		if (!(ty & TF_PARAM_TYPE_OUTPUT_FLAG)) {
			/* input-only or none, so nothing to do */
		} else if (ty & TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG) {
			op->memref.size = params[i].size.size;
		} else if (ty & TF_PARAM_TYPE_MEMREF_FLAG) {
			op->tmpref.size = params[i].size.size;
		} else {
			op->value.a = params[i].value.a;
			op->value.b = params[i].value.b;
		}
	}
}
Exemple #3
0
/*
 * Opens a client session to the Secure World
 */
int tf_open_client_session(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;
	struct tf_shmem_desc *shmem_desc[4] = {NULL};
	u32 i;

	dprintk(KERN_INFO "tf_open_client_session(%p)\n", connection);

	/*
	 * Initialize the message size with no login data. This will be later
	 * adjusted the the cases below
	 */
	command->open_client_session.message_size =
		(sizeof(struct tf_command_open_client_session) - 20
			- sizeof(struct tf_command_header))/4;

	switch (command->open_client_session.login_type) {
	case TF_LOGIN_PUBLIC:
		 /* Nothing to do */
		 break;

	case TF_LOGIN_USER:
		/*
		 * Send the EUID of the calling application in the login data.
		 * Update message size.
		 */
		*(u32 *) &command->open_client_session.login_data =
			current_euid();
#ifndef CONFIG_ANDROID
		command->open_client_session.login_type =
			(u32) TF_LOGIN_USER_LINUX_EUID;
#else
		command->open_client_session.login_type =
			(u32) TF_LOGIN_USER_ANDROID_EUID;
#endif

		/* Added one word */
		command->open_client_session.message_size += 1;
		break;

	case TF_LOGIN_GROUP: {
		/* Check requested GID */
		gid_t  requested_gid =
			*(u32 *) command->open_client_session.login_data;

		if (!tf_check_gid(requested_gid)) {
			dprintk(KERN_ERR "tf_open_client_session(%p) "
				"TF_LOGIN_GROUP: requested GID (0x%x) does "
				"not match real eGID (0x%x)"
				"or any of the supplementary GIDs\n",
				connection, requested_gid, current_egid());
			error = -EACCES;
			goto error;
		}
#ifndef CONFIG_ANDROID
		command->open_client_session.login_type =
			TF_LOGIN_GROUP_LINUX_GID;
#else
		command->open_client_session.login_type =
			TF_LOGIN_GROUP_ANDROID_GID;
#endif

		command->open_client_session.message_size += 1; /* GID */
		break;
	}

#ifndef CONFIG_ANDROID
	case TF_LOGIN_APPLICATION: {
		/*
		 * Compute SHA-1 hash of the application fully-qualified path
		 * name.  Truncate the hash to 16 bytes and send it as login
		 * data.  Update message size.
		 */
		u8 pSHA1Hash[SHA1_DIGEST_SIZE];

		error = tf_hash_application_path_and_data(pSHA1Hash,
			NULL, 0);
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_hash_application_path_and_data\n");
			goto error;
		}
		memcpy(&command->open_client_session.login_data,
			pSHA1Hash, 16);
		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH;
		/* 16 bytes */
		command->open_client_session.message_size += 4;
		break;
	}
#else
	case TF_LOGIN_APPLICATION:
		/*
		 * Send the real UID of the calling application in the login
		 * data. Update message size.
		 */
		*(u32 *) &command->open_client_session.login_data =
			current_uid();

		command->open_client_session.login_type =
			(u32) TF_LOGIN_APPLICATION_ANDROID_UID;

		/* Added one word */
		command->open_client_session.message_size += 1;
		break;
#endif

#ifndef CONFIG_ANDROID
	case TF_LOGIN_APPLICATION_USER: {
		/*
		 * Compute SHA-1 hash of the concatenation of the application
		 * fully-qualified path name and the EUID of the calling
		 * application.  Truncate the hash to 16 bytes and send it as
		 * login data.  Update message size.
		 */
		u8 pSHA1Hash[SHA1_DIGEST_SIZE];

		error = tf_hash_application_path_and_data(pSHA1Hash,
			(u8 *) &(current_euid()), sizeof(current_euid()));
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_hash_application_path_and_data\n");
			goto error;
		}
		memcpy(&command->open_client_session.login_data,
			pSHA1Hash, 16);
		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH;

		/* 16 bytes */
		command->open_client_session.message_size += 4;

		break;
	}
#else
	case TF_LOGIN_APPLICATION_USER:
		/*
		 * Send the real UID and the EUID of the calling application in
		 * the login data. Update message size.
		 */
		*(u32 *) &command->open_client_session.login_data =
			current_uid();
		*(u32 *) &command->open_client_session.login_data[4] =
			current_euid();

		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_USER_ANDROID_UID_EUID;

		/* Added two words */
		command->open_client_session.message_size += 2;
		break;
#endif

#ifndef CONFIG_ANDROID
	case TF_LOGIN_APPLICATION_GROUP: {
		/*
		 * Check requested GID.  Compute SHA-1 hash of the concatenation
		 * of the application fully-qualified path name and the
		 * requested GID.  Update message size
		 */
		gid_t  requested_gid;
		u8     pSHA1Hash[SHA1_DIGEST_SIZE];

		requested_gid =	*(u32 *) &command->open_client_session.
			login_data;

		if (!tf_check_gid(requested_gid)) {
			dprintk(KERN_ERR "tf_open_client_session(%p) "
			"TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) "
			"does not match real eGID (0x%x)"
			"or any of the supplementary GIDs\n",
			connection, requested_gid, current_egid());
			error = -EACCES;
			goto error;
		}

		error = tf_hash_application_path_and_data(pSHA1Hash,
			&requested_gid, sizeof(u32));
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_hash_application_path_and_data\n");
			goto error;
		}

		memcpy(&command->open_client_session.login_data,
			pSHA1Hash, 16);
		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH;

		/* 16 bytes */
		command->open_client_session.message_size += 4;
		break;
	}
#else
	case TF_LOGIN_APPLICATION_GROUP: {
		/*
		 * Check requested GID. Send the real UID and the requested GID
		 * in the login data. Update message size.
		 */
		gid_t requested_gid;

		requested_gid =	*(u32 *) &command->open_client_session.
			login_data;

		if (!tf_check_gid(requested_gid)) {
			dprintk(KERN_ERR "tf_open_client_session(%p) "
			"TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) "
			"does not match real eGID (0x%x)"
			"or any of the supplementary GIDs\n",
			connection, requested_gid, current_egid());
			error = -EACCES;
			goto error;
		}

		*(u32 *) &command->open_client_session.login_data =
			current_uid();
		*(u32 *) &command->open_client_session.login_data[4] =
			requested_gid;

		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID;

		/* Added two words */
		command->open_client_session.message_size += 2;

		break;
	}
#endif

	case TF_LOGIN_PRIVILEGED:
		/* A privileged login may be performed only on behalf of the
		   kernel itself or on behalf of a process with euid=0 or
		   egid=0 or euid=system or egid=system. */
		if (connection->owner == TF_CONNECTION_OWNER_KERNEL) {
			dprintk(KERN_DEBUG "tf_open_client_session: "
				"TF_LOGIN_PRIVILEGED for kernel API\n");
		} else if ((current_euid() != TF_PRIVILEGED_UID_GID) &&
			   (current_egid() != TF_PRIVILEGED_UID_GID) &&
			   (current_euid() != 0) && (current_egid() != 0)) {
			dprintk(KERN_ERR "tf_open_client_session: "
				" user %d, group %d not allowed to open "
				"session with TF_LOGIN_PRIVILEGED\n",
				current_euid(), current_egid());
			error = -EACCES;
			goto error;
		} else {
			dprintk(KERN_DEBUG "tf_open_client_session: "
				"TF_LOGIN_PRIVILEGED for %u:%u\n",
				current_euid(), current_egid());
		}
		command->open_client_session.login_type =
			TF_LOGIN_PRIVILEGED;
		break;

	case TF_LOGIN_AUTHENTICATION: {
		/*
		 * Compute SHA-1 hash of the application binary
		 * Send this hash as the login data (20 bytes)
		 */

		u8 *hash;
		hash = &(command->open_client_session.login_data[0]);

		error = tf_get_current_process_hash(hash);
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_get_current_process_hash\n");
			goto error;
		}
		command->open_client_session.login_type =
			TF_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH;

		/* 20 bytes */
		command->open_client_session.message_size += 5;
		break;
	}

	case TF_LOGIN_PRIVILEGED_KERNEL:
		/* A kernel login may be performed only on behalf of the
		   kernel itself. */
		if (connection->owner == TF_CONNECTION_OWNER_KERNEL) {
			dprintk(KERN_DEBUG "tf_open_client_session: "
				"TF_LOGIN_PRIVILEGED_KERNEL for kernel API\n");
			command->open_client_session.login_type =
				TF_LOGIN_PRIVILEGED_KERNEL;
		} else {
			dprintk(KERN_ERR "tf_open_client_session: "
				" user %d, group %d not allowed to open "
				"session with TF_LOGIN_PRIVILEGED_KERNEL\n",
				current_euid(), current_egid());
			error = -EACCES;
			goto error;
		}
		command->open_client_session.login_type =
			TF_LOGIN_PRIVILEGED_KERNEL;
		break;

	default:
		 dprintk(KERN_ERR "tf_open_client_session: "
			"unknown login_type(%08X)\n",
			command->open_client_session.login_type);
		 error = -EOPNOTSUPP;
		 goto error;
	}

	/* Map the temporary memory references */
	for (i = 0; i < 4; i++) {
		int param_type;
		param_type = TF_GET_PARAM_TYPE(
			command->open_client_session.param_types, i);
		if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG |
				   TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG))
				== TF_PARAM_TYPE_MEMREF_FLAG) {
			/* Map temp mem ref */
			error = tf_map_temp_shmem(connection,
				&command->open_client_session.
					params[i].temp_memref,
				param_type,
				&shmem_desc[i]);
			if (error != 0) {
				dprintk(KERN_ERR "tf_open_client_session: "
					"unable to map temporary memory block "
					"(%08X)\n", error);
				goto error;
			}
		}
	}

	/* Fill the handle of the Device Context */
	command->open_client_session.device_context =
		connection->device_context;

	error = tf_send_receive(
		&connection->dev->sm,
		command,
		answer,
		connection,
		true);

error:
	/* Unmap the temporary memory references */
	for (i = 0; i < 4; i++)
		if (shmem_desc[i] != NULL)
			tf_unmap_shmem(connection, shmem_desc[i], 0);

	if (error != 0)
		dprintk(KERN_ERR "tf_open_client_session returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_open_client_session returns "
			"error_code 0x%08X\n",
			answer->open_client_session.error_code);

	return error;
}
Exemple #4
0
/*
 * Invokes a client command to the Secure World
 */
int tf_invoke_client_command(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;
	struct tf_shmem_desc *shmem_desc[4] = {NULL};
	int i;
#ifdef CONFIG_TF_ION
	struct ion_handle *new_handle = NULL;
#endif /* CONFIG_TF_ION */

	dprintk(KERN_INFO "tf_invoke_client_command(%p)\n", connection);

	command->release_shared_memory.message_size =
		(sizeof(struct tf_command_invoke_client_command) -
			sizeof(struct tf_command_header)) / 4;

#ifdef CONFIG_TF_ZEBRA
	error = tf_crypto_try_shortcuted_update(connection,
		(struct tf_command_invoke_client_command *) command,
		(struct tf_answer_invoke_client_command *) answer);
	if (error == 0)
		return error;
#endif

	/* Map the tmprefs */
	for (i = 0; i < 4; i++) {
		int param_type = TF_GET_PARAM_TYPE(
			command->invoke_client_command.param_types, i);

		if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG |
					TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG))
				== TF_PARAM_TYPE_MEMREF_FLAG) {
			/* A temporary memref: map it */
			error = tf_map_temp_shmem(connection,
					&command->invoke_client_command.
						params[i].temp_memref,
					param_type, &shmem_desc[i]);
			if (error != 0) {
				dprintk(KERN_ERR
					"tf_invoke_client_command: "
					"unable to map temporary memory "
					"block\n (%08X)", error);
				goto error;
			}
		}
#ifdef CONFIG_TF_ION
		else if (param_type == TF_PARAM_TYPE_MEMREF_ION_HANDLE) {
			struct tf_command_invoke_client_command *invoke;
			ion_phys_addr_t ion_addr;
			size_t ion_len;
			struct ion_buffer *buffer;

			if (connection->ion_client == NULL) {
				connection->ion_client = ion_client_create(
					zebra_ion_device,
					(1 << ION_HEAP_TYPE_CARVEOUT),
					"tf");
			}
			if (connection->ion_client == NULL) {
				dprintk(KERN_ERR "%s(%p): "
					"unable to create ion client\n",
					__func__, connection);
				error = -EFAULT;
				goto error;
			}

			invoke = &command->invoke_client_command;

			dprintk(KERN_INFO "ion_handle %x",
				invoke->params[i].value.a);
			buffer = ion_share(connection->ion_client,
				(struct ion_handle *)invoke->params[i].value.a);
			if (buffer == NULL) {
				dprintk(KERN_ERR "%s(%p): "
					"unable to share ion handle\n",
					__func__, connection);
				error = -EFAULT;
				goto error;
			}

			dprintk(KERN_INFO "ion_buffer %p", buffer);
			new_handle = ion_import(connection->ion_client, buffer);
			if (new_handle == NULL) {
				dprintk(KERN_ERR "%s(%p): "
					"unable to import ion buffer\n",
					__func__, connection);
				error = -EFAULT;
				goto error;
			}

			dprintk(KERN_INFO "new_handle %x", new_handle);
			error = ion_phys(connection->ion_client,
					new_handle,
					&ion_addr,
					&ion_len);
			if (error) {
				dprintk(KERN_ERR
				"%s: unable to convert ion handle "
				"0x%08X (error code 0x%08X)\n",
				__func__,
				new_handle,
				error);
				error = -EINVAL;
				goto error;
			}
			dprintk(KERN_INFO
			"%s: handle=0x%08x phys_add=0x%08x length=0x%08x\n",
			__func__, invoke->params[i].value.a, ion_addr, ion_len);

			invoke->params[i].value.a = (u32) ion_addr;
			invoke->params[i].value.b = (u32) ion_len;

			invoke->param_types &= ~((0xF) << (4*i));
			invoke->param_types |=
				TF_PARAM_TYPE_VALUE_INPUT << (4*i);
		}
#endif /* CONFIG_TF_ION */
	}

	command->invoke_client_command.device_context =
		connection->device_context;

	error = tf_send_receive(&connection->dev->sm, command,
		answer, connection, true);

error:
#ifdef CONFIG_TF_ION
	if (new_handle != NULL)
		ion_free(connection->ion_client, new_handle);
#endif /* CONFIG_TF_ION */
	/* Unmap de temp mem refs */
	for (i = 0; i < 4; i++) {
		if (shmem_desc[i] != NULL) {
			dprintk(KERN_INFO "tf_invoke_client_command: "
				"UnMatemp_memref %d\n ", i);

			tf_unmap_shmem(connection, shmem_desc[i], 0);
		}
	}

	if (error != 0)
		dprintk(KERN_ERR "tf_invoke_client_command returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_invoke_client_command returns "
			"error_code 0x%08X\n",
			answer->invoke_client_command.error_code);

	return error;
}