Linux内核套接字编程:sendmsg函数无法访问msg地址



我想在内核模块中使用socket->ops->sendmsg()发送消息。函数sendmsg struct msghdr的一个参数有一个指向发送缓冲区的指针msg_iov

但除了NULL,无论我分配给msg_iov的缓冲区地址,sendmsg()都会返回EFAULT错误给我。这意味着我分配给指针的地址不能被访问。

所以请帮助我,非常感谢。
附注:这是我的一部分代码。我省略了不相关的代码。

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] = '';  
down_write(&current->mm->mmap_sem);
user_addr = do_mmap_pgoff(NULL, 0, count, PROT_READ|PROT_WRITE,
                           MAP_PRIVATE|MAP_ANONYMOUS, 0);
up_write(&current->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( &current->mm, user_addr, strlen( (char*) user_addr));

不能用内核地址空间中的数据调用这个函数:

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在x86上检查userspace指针:

/**
 * 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))

__range_not_ok()的注释看起来很相似:

/*
 * 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...
 */

当涉及到特定于体系结构的代码时,我遵循特定于x86的代码路径,我希望其他体系结构能够尽其所能地执行此行为。

在内核struct iovec内存上不能调用sendmsg()

最新更新