Commit 146bf4e7 authored by Etienne Carriere's avatar Etienne Carriere Committed by Jens Wiklander
Browse files

tee: new ioctl to a register tee_shm from a dmabuf file descriptor



Add a userspace API to create a tee_shm object that refers to a dmabuf
reference.

Userspace registers the dmabuf file descriptor as in a tee_shm object.
The registration is completed with a tee_shm returned file descriptor.

Userspace is free to close the dmabuf file descriptor after it has been
registered since all the resources are now held via the new tee_shm
object.

Closing the tee_shm file descriptor will eventually release all
resources used by the tee_shm object when all references are released.

The new IOCTL, TEE_IOC_SHM_REGISTER_FD, supports dmabuf references to
physically contiguous memory buffers. Dmabuf references acquired from
the TEE DMA-heap can be used as protected memory for Secure Video Path
and such use cases. It depends on the TEE and the TEE driver if dmabuf
references acquired by other means can be used.

A new tee_shm flag is added to identify tee_shm objects built from a
registered dmabuf, TEE_SHM_DMA_BUF.

Signed-off-by: default avatarEtienne Carriere <etienne.carriere@foss.st.com>
Signed-off-by: default avatarOlivier Masse <olivier.masse@nxp.com>
Reviewed-by: default avatarSumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: default avatarJens Wiklander <jens.wiklander@linaro.org>
parent fdf631ac
Loading
Loading
Loading
Loading
+61 −1
Original line number Diff line number Diff line
@@ -354,11 +354,49 @@ tee_ioctl_shm_register(struct tee_context *ctx,
	return ret;
}

static int
tee_ioctl_shm_register_fd(struct tee_context *ctx,
			  struct tee_ioctl_shm_register_fd_data __user *udata)
{
	struct tee_ioctl_shm_register_fd_data data;
	struct tee_shm *shm;
	long ret;

	if (copy_from_user(&data, udata, sizeof(data)))
		return -EFAULT;

	/* Currently no input flags are supported */
	if (data.flags)
		return -EINVAL;

	shm = tee_shm_register_fd(ctx, data.fd);
	if (IS_ERR(shm))
		return -EINVAL;

	data.id = shm->id;
	data.flags = shm->flags;
	data.size = shm->size;

	if (copy_to_user(udata, &data, sizeof(data)))
		ret = -EFAULT;
	else
		ret = tee_shm_get_fd(shm);

	/*
	 * When user space closes the file descriptor the shared memory
	 * should be freed or if tee_shm_get_fd() failed then it will
	 * be freed immediately.
	 */
	tee_shm_put(shm);
	return ret;
}

static int param_from_user_memref(struct tee_context *ctx,
				  struct tee_param_memref *memref,
				  struct tee_ioctl_param *ip)
{
	struct tee_shm *shm;
	size_t offs = 0;

	/*
	 * If a NULL pointer is passed to a TA in the TEE,
@@ -389,6 +427,26 @@ static int param_from_user_memref(struct tee_context *ctx,
			tee_shm_put(shm);
			return -EINVAL;
		}

		if (shm->flags & TEE_SHM_DMA_BUF) {
			struct tee_shm_dmabuf_ref *ref;

			ref = container_of(shm, struct tee_shm_dmabuf_ref, shm);
			if (ref->parent_shm) {
				/*
				 * The shm already has one reference to
				 * ref->parent_shm so we are clear of 0.
				 * We're getting another reference since
				 * this shm will be used in the parameter
				 * list instead of the shm we got with
				 * tee_shm_get_from_id() above.
				 */
				refcount_inc(&ref->parent_shm->refcount);
				tee_shm_put(shm);
				shm = ref->parent_shm;
				offs = ref->offset;
			}
		}
	} else if (ctx->cap_memref_null) {
		/* Pass NULL pointer to OP-TEE */
		shm = NULL;
@@ -396,7 +454,7 @@ static int param_from_user_memref(struct tee_context *ctx,
		return -EINVAL;
	}

	memref->shm_offs = ip->a;
	memref->shm_offs = ip->a + offs;
	memref->size = ip->b;
	memref->shm = shm;

@@ -842,6 +900,8 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		return tee_ioctl_shm_alloc(ctx, uarg);
	case TEE_IOC_SHM_REGISTER:
		return tee_ioctl_shm_register(ctx, uarg);
	case TEE_IOC_SHM_REGISTER_FD:
		return tee_ioctl_shm_register_fd(ctx, uarg);
	case TEE_IOC_OPEN_SESSION:
		return tee_ioctl_open_session(ctx, uarg);
	case TEE_IOC_INVOKE:
+8 −0
Original line number Diff line number Diff line
@@ -13,6 +13,14 @@
#include <linux/mutex.h>
#include <linux/types.h>

/* extra references appended to shm object for registered shared memory */
struct tee_shm_dmabuf_ref {
	struct tee_shm shm;
	size_t offset;
	struct dma_buf *dmabuf;
	struct tee_shm *parent_shm;
};

int tee_shm_get_fd(struct tee_shm *shm);

bool tee_device_get(struct tee_device *teedev);
+71 −3
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 */
#include <linux/anon_inodes.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/idr.h>
#include <linux/io.h>
#include <linux/mm.h>
@@ -45,7 +46,15 @@ static void release_registered_pages(struct tee_shm *shm)

static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
{
	if (shm->flags & TEE_SHM_POOL) {
	void *p = shm;

	if (shm->flags & TEE_SHM_DMA_BUF) {
		struct tee_shm_dmabuf_ref *ref;

		ref = container_of(shm, struct tee_shm_dmabuf_ref, shm);
		p = ref;
		dma_buf_put(ref->dmabuf);
	} else if (shm->flags & TEE_SHM_POOL) {
		teedev->pool->ops->free(teedev->pool, shm);
	} else if (shm->flags & TEE_SHM_DYNAMIC) {
		int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
@@ -59,7 +68,7 @@ static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)

	teedev_ctx_put(shm->ctx);

	kfree(shm);
	kfree(p);

	tee_device_put(teedev);
}
@@ -169,7 +178,7 @@ struct tee_shm *tee_shm_alloc_user_buf(struct tee_context *ctx, size_t size)
 * tee_client_invoke_func(). The memory allocated is later freed with a
 * call to tee_shm_free().
 *
 * @returns a pointer to 'struct tee_shm'
 * @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure
 */
struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size)
{
@@ -179,6 +188,62 @@ struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size)
}
EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf);

struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd)
{
	struct tee_shm_dmabuf_ref *ref;
	int rc;

	if (!tee_device_get(ctx->teedev))
		return ERR_PTR(-EINVAL);

	teedev_ctx_get(ctx);

	ref = kzalloc(sizeof(*ref), GFP_KERNEL);
	if (!ref) {
		rc = -ENOMEM;
		goto err_put_tee;
	}

	refcount_set(&ref->shm.refcount, 1);
	ref->shm.ctx = ctx;
	ref->shm.id = -1;
	ref->shm.flags = TEE_SHM_DMA_BUF;

	ref->dmabuf = dma_buf_get(fd);
	if (IS_ERR(ref->dmabuf)) {
		rc = PTR_ERR(ref->dmabuf);
		goto err_kfree_ref;
	}

	rc = tee_heap_update_from_dma_buf(ctx->teedev, ref->dmabuf,
					  &ref->offset, &ref->shm,
					  &ref->parent_shm);
	if (rc)
		goto err_put_dmabuf;

	mutex_lock(&ref->shm.ctx->teedev->mutex);
	ref->shm.id = idr_alloc(&ref->shm.ctx->teedev->idr, &ref->shm,
				1, 0, GFP_KERNEL);
	mutex_unlock(&ref->shm.ctx->teedev->mutex);
	if (ref->shm.id < 0) {
		rc = ref->shm.id;
		goto err_put_dmabuf;
	}

	return &ref->shm;

err_put_dmabuf:
	dma_buf_put(ref->dmabuf);
err_kfree_ref:
	kfree(ref);
err_put_tee:
	teedev_ctx_put(ctx);
	tee_device_put(ctx->teedev);

	return ERR_PTR(rc);
}
EXPORT_SYMBOL_GPL(tee_shm_register_fd);

/**
 * tee_shm_alloc_priv_buf() - Allocate shared memory for a privately shared
 *			      kernel buffer
@@ -442,6 +507,9 @@ static int tee_shm_fop_mmap(struct file *filp, struct vm_area_struct *vma)
	/* Refuse sharing shared memory provided by application */
	if (shm->flags & TEE_SHM_USER_MAPPED)
		return -EINVAL;
	/* Refuse sharing registered DMA_bufs with the application */
	if (shm->flags & TEE_SHM_DMA_BUF)
		return -EINVAL;

	/* check for overflowing the buffer's size */
	if (vma->vm_pgoff + vma_pages(vma) > shm->size >> PAGE_SHIFT)
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#define TEE_SHM_USER_MAPPED	BIT(1)  /* Memory mapped in user space */
#define TEE_SHM_POOL		BIT(2)  /* Memory allocated from pool */
#define TEE_SHM_PRIV		BIT(3)  /* Memory private to TEE driver */
#define TEE_SHM_DMA_BUF		BIT(4)	/* Memory with dma-buf handle */

#define TEE_DEVICE_FLAG_REGISTERED	0x1
#define TEE_MAX_DEV_NAME_LEN		32
+10 −0
Original line number Diff line number Diff line
@@ -116,6 +116,16 @@ struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size);
struct tee_shm *tee_shm_register_kernel_buf(struct tee_context *ctx,
					    void *addr, size_t length);

/**
 * tee_shm_register_fd() - Register shared memory from file descriptor
 *
 * @ctx:	Context that allocates the shared memory
 * @fd:		Shared memory file descriptor reference
 *
 * @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure
 */
struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd);

/**
 * tee_shm_free() - Free shared memory
 * @shm:	Handle to shared memory to free
Loading