static int message_copy_from_user()

in nsm-driver/nsm.c [114:159]


static int message_copy_from_user(struct nsm_kernel_message *dst,
	struct nsm_message *src)
{
	struct nsm_message shallow_copy;

	if (!src || !dst)
		return -EINVAL;

	/* The destination's request and response buffers should be NULL. */
	if (dst->request.iov_base || dst->response.iov_base)
		return -EINVAL;

	/* First, make a shallow copy to be able to read the inner pointers */
	if (copy_from_user(&shallow_copy, src, sizeof(shallow_copy)) != 0)
		return -EINVAL;

	/* Verify the user input size. */
	if (shallow_copy.request.iov_len > NSM_REQUEST_MAX_SIZE)
		return -EMSGSIZE;

	/* Allocate kernel memory for the user request */
	dst->request.iov_len = shallow_copy.request.iov_len;
	dst->request.iov_base = kmalloc(dst->request.iov_len, GFP_KERNEL);
	if (!dst->request.iov_base)
		return -ENOMEM;

	/* Copy the request content */
	if (copy_from_user(dst->request.iov_base,
		shallow_copy.request.iov_base, dst->request.iov_len) != 0) {
		kfree(dst->request.iov_base);
		return -EFAULT;
	}

	/* Allocate kernel memory for the response, up to a fixed limit */
	dst->response.iov_len = shallow_copy.response.iov_len;
	if (dst->response.iov_len > NSM_RESPONSE_MAX_SIZE)
		dst->response.iov_len = NSM_RESPONSE_MAX_SIZE;

	dst->response.iov_base = kmalloc(dst->response.iov_len, GFP_KERNEL);
	if (!dst->response.iov_base) {
		kfree(dst->request.iov_base);
		return -ENOMEM;
	}

	return 0;
}