Reputation: 169
I want to send a message with socket->ops->sendmsg()
in kernel module. One of the arguments of func sendmsg struct msghdr
has a pointer msg_iov
to the send buffer.
But except NULL
, whatever buffer address I assign to the msg_iov
the sendmsg() will return a EFAULT error to me. That means the address I assigned to the pointer can not be accessed.
So please help me and thank you very much.
P.S: here is part of my code. I omitted the irrelevant codes.
struct iovec vec;
char *buff = (char *)kmalloc(7, GFP_KERNEL);
unsigned long user_addr=0;
size_t count = 16;
buff[0] = 'H';
buff[1] = 'e';
buff[2] = 'l';
buff[3] = 'l';
buff[4] = 'o';
buff[5] = '\n';
buff[6] = '\0';
down_write(¤t->mm->mmap_sem);
user_addr = do_mmap_pgoff(NULL, 0, count, PROT_READ|PROT_WRITE,\
MAP_PRIVATE|MAP_ANONYMOUS, 0);
up_write(¤t->mm->mmap_sem);
__copy_to_user((void*)user_addr, (void*)buff, 7);
vec.iov_base = (void*)user_addr;
vec.iov_len = strlen( (char*)user_addr );
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
error = NewSock->ops->sendmsg(&kiocb,NewSock, &msg, 7);
do_munmap( ¤t->mm, user_addr, strlen( (char*) user_addr));
Upvotes: 1
Views: 2605
Reputation: 104080
You can't call this function with data that lives in the kernel's address space:
int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
/* ... */
while (--iovlen >= 0) {
size_t seglen = iov->iov_len;
unsigned char __user *from = iov->iov_base;
/* ... */
if ((err = skb_add_data(skb, from, copy)) != 0)
goto do_fault;
static inline int skb_add_data(struct sk_buff *skb,
char __user *from, int copy)
/* ... */
__wsum csum = csum_and_copy_from_user(from, skb_put(skb, copy),
copy, 0, &err);
#define csum_and_copy_from_user csum_partial_copy_from_user
__wsum
csum_partial_copy_from_user(const void __user *src, void *dst,
int len, __wsum isum, int *errp)
/* ... */
if (!likely(access_ok(VERIFY_READ, src, len)))
goto out_err;
/* ... */
isum = csum_partial_copy_generic((__force const void *)src,
dst, len, isum, errp, NULL);
access_ok
on x86 checks for userspace pointers:
/**
* access_ok: - Checks if a user space pointer is valid
* @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
* %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
* to write to a block, it is always safe to read from it.
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
* Context: User context only. This function may sleep.
*
* Checks if a pointer to a block of memory in user space is valid.
*
* Returns true (nonzero) if the memory block may be valid, false (zero)
* if it is definitely invalid.
*
* Note that, depending on architecture, this function probably just
* checks that the pointer is in the user space range - after calling
* this function, memory access functions may still return -EFAULT.
*/
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
The comment on __range_not_ok()
looks similar:
/*
* Test whether a block of memory is a valid user space address.
* Returns 0 if the range is valid, nonzero otherwise.
*
* This is equivalent to the following test:
* (u33)addr + (u33)size >= (u33)current->addr_limit.seg (u65 for x86_64)
*
* This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry...
*/
While I followed the x86-specific code paths whenever architecture-specific code was involved, I expect other architectures to enforce this behavior to the best of their respective abilities.
It looks like you cannot call sendmsg()
on in-kernel struct iovec
memory.
Upvotes: 2