/* * TEE Client UUID name space identifier (UUIDv4) * * Value here is random UUID that is allocated as name space identifier for * forming Client UUID's for TEE environment using UUIDv5 scheme.
*/ staticconst uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683,
0xa1, 0xb8, 0xec, 0x4b,
0xc0, 0x8e, 0x01, 0xb6);
/* * Unprivileged devices in the lower half range and privileged devices in * the upper half range.
*/ static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); static DEFINE_SPINLOCK(driver_lock);
ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev)); if (IS_ERR(ctx)) return PTR_ERR(ctx);
/* * Default user-space behaviour is to wait for tee-supplicant * if not present for any requests in this context.
*/
ctx->supp_nowait = false;
filp->private_data = ctx; return 0;
}
/** * uuid_v5() - Calculate UUIDv5 * @uuid: Resulting UUID * @ns: Name space ID for UUIDv5 function * @name: Name for UUIDv5 function * @size: Size of name * * UUIDv5 is specific in RFC 4122. * * This implements section (for SHA-1): * 4.3. Algorithm for Creating a Name-Based UUID
*/ staticint uuid_v5(uuid_t *uuid, const uuid_t *ns, constvoid *name,
size_t size)
{ unsignedchar hash[SHA1_DIGEST_SIZE]; struct crypto_shash *shash = NULL; struct shash_desc *desc = NULL; int rc;
int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, const u8 connection_data[TEE_IOCTL_UUID_LEN])
{
gid_t ns_grp = (gid_t)-1;
kgid_t grp = INVALID_GID; char *name = NULL; int name_len; int rc;
if (connection_method == TEE_IOCTL_LOGIN_PUBLIC ||
connection_method == TEE_IOCTL_LOGIN_REE_KERNEL) { /* Nil UUID to be passed to TEE environment */
uuid_copy(uuid, &uuid_null); return 0;
}
/* * In Linux environment client UUID is based on UUIDv5. * * Determine client UUID with following semantics for 'name': * * For TEEC_LOGIN_USER: * uid=<uid> * * For TEEC_LOGIN_GROUP: * gid=<gid> *
*/
name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL); if (!name) return -ENOMEM;
if (copy_from_user(&data, udata, sizeof(data))) return -EFAULT;
/* Currently no input flags are supported */ if (data.flags) return -EINVAL;
shm = tee_shm_alloc_user_buf(ctx, data.size); if (IS_ERR(shm)) return PTR_ERR(shm);
data.id = shm->id;
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;
}
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_user_buf(ctx, data.addr, data.length); if (IS_ERR(shm)) return PTR_ERR(shm);
data.id = shm->id;
data.length = 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;
}
for (n = 0; n < num_params; n++) { struct tee_shm *shm; struct tee_ioctl_param ip;
if (copy_from_user(&ip, uparams + n, sizeof(ip))) return -EFAULT;
/* All unused attribute bits has to be zero */ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK) return -EINVAL;
params[n].attr = ip.attr; switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: break; case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
params[n].u.value.a = ip.a;
params[n].u.value.b = ip.b;
params[n].u.value.c = ip.c; break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: /* * If a NULL pointer is passed to a TA in the TEE, * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL * indicating a NULL memory reference.
*/ if (ip.c != TEE_MEMREF_NULL) { /* * If we fail to get a pointer to a shared * memory object (and increase the ref count) * from an identifier we return an error. All * pointers that has been added in params have * an increased ref count. It's the callers * responibility to do tee_shm_put() on all * resolved pointers.
*/
shm = tee_shm_get_from_id(ctx, ip.c); if (IS_ERR(shm)) return PTR_ERR(shm);
/* * Ensure offset + size does not overflow * offset and does not overflow the size of * the referred shared memory object.
*/ if ((ip.a + ip.b) < ip.a ||
(ip.a + ip.b) > shm->size) {
tee_shm_put(shm); return -EINVAL;
}
} elseif (ctx->cap_memref_null) { /* Pass NULL pointer to OP-TEE */
shm = NULL;
} else { return -EINVAL;
}
if (put_user(arg.session, &uarg->session) ||
put_user(arg.ret, &uarg->ret) ||
put_user(arg.ret_origin, &uarg->ret_origin)) {
rc = -EFAULT; goto out;
}
rc = params_to_user(uparams, arg.num_params, params);
out: /* * If we've succeeded to open the session but failed to communicate * it back to user space, close the session again to avoid leakage.
*/ if (rc && have_session && ctx->teedev->desc->ops->close_session)
ctx->teedev->desc->ops->close_session(ctx, arg.session);
if (params) { /* Decrease ref count for all valid shared memory pointers */ for (n = 0; n < arg.num_params; n++) if (tee_param_is_memref(params + n) &&
params[n].u.memref.shm)
tee_shm_put(params[n].u.memref.shm);
kfree(params);
}
for (n = 0; n < num_params; n++) { struct tee_param *p = params + n; struct tee_ioctl_param ip;
if (copy_from_user(&ip, uparams + n, sizeof(ip))) return -EFAULT;
/* All unused attribute bits has to be zero */ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK) return -EINVAL;
p->attr = ip.attr; switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: /* Only out and in/out values can be updated */
p->u.value.a = ip.a;
p->u.value.b = ip.b;
p->u.value.c = ip.c; break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: /* * Only the size of the memref can be updated. * Since we don't have access to the original * parameters here, only store the supplied size. * The driver will copy the updated size into the * original parameters.
*/
p->u.memref.shm = NULL;
p->u.memref.shm_offs = 0;
p->u.memref.size = ip.b; break; default:
memset(&p->u, 0, sizeof(p->u)); break;
}
} return 0;
}
/** * tee_device_alloc() - Allocate a new struct tee_device instance * @teedesc: Descriptor for this driver * @dev: Parent device for this device * @pool: Shared memory pool, NULL if not used * @driver_data: Private driver data for this device * * Allocates a new struct tee_device instance. The device is * removed by tee_device_unregister(). * * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure
*/ struct tee_device *tee_device_alloc(conststruct tee_desc *teedesc, struct device *dev, struct tee_shm_pool *pool, void *driver_data)
{ struct tee_device *teedev; void *ret; int rc, max_id; int offs = 0;
/* 1 as tee_device_unregister() does one final tee_device_put() */
teedev->num_users = 1;
init_completion(&teedev->c_no_users);
mutex_init(&teedev->mutex);
idr_init(&teedev->idr);
/** * tee_device_register() - Registers a TEE device * @teedev: Device to register * * tee_device_unregister() need to be called to remove the @teedev if * this function fails. * * @returns < 0 on failure
*/ int tee_device_register(struct tee_device *teedev)
{ int rc;
if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
dev_err(&teedev->dev, "attempt to register twice\n"); return -EINVAL;
}
rc = cdev_device_add(&teedev->cdev, &teedev->dev); if (rc) {
dev_err(&teedev->dev, "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
teedev->name, MAJOR(teedev->dev.devt),
MINOR(teedev->dev.devt), rc); return rc;
}
void tee_device_put(struct tee_device *teedev)
{
mutex_lock(&teedev->mutex); /* Shouldn't put in this state */ if (!WARN_ON(!teedev->desc)) {
teedev->num_users--; if (!teedev->num_users) {
teedev->desc = NULL;
complete(&teedev->c_no_users);
}
}
mutex_unlock(&teedev->mutex);
}
/** * tee_device_unregister() - Removes a TEE device * @teedev: Device to unregister * * This function should be called to remove the @teedev even if * tee_device_register() hasn't been called yet. Does nothing if * @teedev is NULL.
*/ void tee_device_unregister(struct tee_device *teedev)
{ if (!teedev) return;
if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED)
cdev_device_del(&teedev->cdev, &teedev->dev);
put_device(put_dev); /* * Default behaviour for in kernel client is to not wait for * tee-supplicant if not present for any requests in this context. * Also this flag could be configured again before call to * tee_client_open_session() if any in kernel client requires * different behaviour.
*/ if (!IS_ERR(ctx))
ctx->supp_nowait = true;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.