in tee_core.c [467:544]
static int tee_ioctl_open_session(struct tee_context *ctx,
struct tee_ioctl_buf_data __user *ubuf)
{
int rc;
size_t n;
struct tee_ioctl_buf_data buf;
struct tee_ioctl_open_session_arg __user *uarg;
struct tee_ioctl_open_session_arg arg;
struct tee_ioctl_param __user *uparams = NULL;
struct tee_param *params = NULL;
bool have_session = false;
if (!ctx->teedev->desc->ops->open_session)
return -EINVAL;
if (copy_from_user(&buf, ubuf, sizeof(buf)))
return -EFAULT;
if (buf.buf_len > TEE_MAX_ARG_SIZE ||
buf.buf_len < sizeof(struct tee_ioctl_open_session_arg))
return -EINVAL;
uarg = u64_to_user_ptr(buf.buf_ptr);
if (copy_from_user(&arg, uarg, sizeof(arg)))
return -EFAULT;
if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
return -EINVAL;
if (arg.num_params) {
params = kcalloc(arg.num_params, sizeof(struct tee_param),
GFP_KERNEL);
if (!params)
return -ENOMEM;
uparams = uarg->params;
rc = params_from_user(ctx, params, arg.num_params, uparams);
if (rc)
goto out;
}
if (arg.clnt_login >= TEE_IOCTL_LOGIN_REE_KERNEL_MIN &&
arg.clnt_login <= TEE_IOCTL_LOGIN_REE_KERNEL_MAX) {
pr_debug("login method not allowed for user-space client\n");
rc = -EPERM;
goto out;
}
rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params);
if (rc)
goto out;
have_session = true;
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);
}
return rc;
}