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

但是,除了NULL之外,无论我为sendmsg()分配给msg_iov的任何缓冲区地址,都会向我返回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] = '\0';

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

x86上的access_ok检查用户空间指针:
/**
 * 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的代码路径,但是我希望其他体系结构能够尽其所能来强制执行此行为。

看来您无法在内核sendmsg()内存中调用struct iovec

关于linux - Linux内核套接字编程:sendmsg function msg address can not access,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8252630/

10-13 08:40