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;
}