当前位置: 首页 > 知识库问答 >
问题:

将ctypes与python结合使用并调用libc-accept时的EFAULT

奚才良
2023-03-14

普通python套接字模块在创建套接字时除了AF_INET不支持协议:

从海星套接字模块.c:

  • 尽管在Linux下支持AF_PACKET、AF_NETLINK和AF_TIPC,但仅支持AF_INET、AF_INET6和AF_UNIX地址族

因此,我已经开始使用ctypes手动调用普通BSD套接字库的套接字、绑定、侦听和直接接受来自libc的调用。我可以创建套接字,将套接字绑定到地址,并将套接符置于侦听模式,这需要转换对我创建的Structure继承的SockAddr_in类的引用:

CharArr14 = c_char * 14                                                                                                       
In_Addr = c_uint32                                                                                                            
CharArr8 = c_char * 8                                                                                                         


class SockAddr(Structure):                                                                                                    
    _fields_ = [                                                                                                              
        ('sa_len', c_uint8),                                                                                                  
        ('sa_family', c_uint8),                                                                                               
        ('sa_data', CharArr14)                                                                                                
    ]                                                                                                                         


class SockAddr_In(Structure):                                                                                                 
    _fields_ = [                                                                                                              
        ('sa_len', c_uint8),                                                                                                  
        ('sa_family', c_uint8),                                                                                               
        ('sin_port', c_uint16),                                                                                               
        ('sin_addr', In_Addr),                                                                                                
        ('sin_zero', CharArr8)                                                                                                
    ]  

但是,当我尝试调用accept时,它传递了一个地址,内核将写入连接套接字的SockAddr_In结构信息,我收到的是EFAULT(errno 14),它对应于错误的内存地址。

def accept_sdp_sock(self):                                                                                                
    accept = libc.accept                                                                                                  
    logger.debug("Accepting socket on: {}".format(self.ip_addr))                                                          
    # int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);                                                  
    # Why is this a bad address? Is it being deallocated?                                                                 
    # Maybe it isn't allocating until we fill it with data?                                                               

    addr = SockAddr_In()                                                                                                  
    logger.debug("Memory address of addr struct: {}".format(addr))                                                        
    afd = accept(self.fd,                                                                                                 
                 cast(byref(addr), POINTER(SockAddr)),                                                                    
                 sizeof(SockAddr_In))                                                                                     
    # Check accept fd for errors                                                                                          
    if afd == -1:                                                                                                         
        self.errno = get_errno()                                                                                          
        logger.debug("Accept call failed: {} ".format(self.errno))                                                        

    return afd

因此,我们看到此输出与程序概述的内存地址

#truss -fead -s65535 -o truss_out python sdp_sock_cmd.py -l --address 192.168.66.140 --debug
2018-02-28 13:59:40,008 - DEBUG - This is a debug message
2018-02-28 13:59:40,009 - INFO - And an info
2018-02-28 13:59:40,009 - DEBUG - Creating SDP socket 
2018-02-28 13:59:40,010 - DEBUG - Binding SDP socket to : 192.168.66.140
2018-02-28 13:59:40,011 - DEBUG - Memory address of addr struct: <ib_socks.SockAddr_In object at 0x80385d9e0>
2018-02-28 13:59:40,012 - DEBUG - Socket listening on: 192.168.66.140
2018-02-28 13:59:40,013 - DEBUG - Accepting socket on: 192.168.66.140
2018-02-28 13:59:40,014 - DEBUG - Memory address of addr struct: <ib_socks.SockAddr_In object at 0x80385d9e0>
2018-02-28 13:59:40,015 - DEBUG - Accept call failed: 14

在桁架输出中,我们看到:

18105: 0.288079361 accept(3,0x80385da30,0x10)    ERR#14 'Bad address'

我尝试过使用libc的malloc进行分配,使用ctypes的create_string_buffer()创建一个字符串缓冲区,但是在这两种情况下我都看到了缺省值。为什么在这种情况下我会看到一个EFAULT?如何使用ctypes在python中分配一个数据结构,以允许内核将数据移动到用户空间?

共有1个答案

萧卜霸
2023-03-14

我看到一个明显的问题。我已经成功地使用了ctypes,但不能自称是专家,所以可能还有其他问题。

我想你一定是在某个地方定义了libc.accept的参数原型,但是你发布的源代码中没有,所以我假设它是正确的。假设原型与libc绑定一致:接受的第三个参数(addrlen)是指向socklen_t的指针,但是你只是传递一个长度(而不是指向长度的指针)。

通常的做法是创建一个socklen_t变量,并用 addr 缓冲区的大小填充它,然后接受(在它完成时)将对等方的地址复制到您的 addr 缓冲区中,如果它太大,则截断,但使用实际大小更新传递的 addrlen。从 (linux 版本) 接受(2)

addrlen参数是一个值结果参数:调用者必须对其进行初始化,以包含addr指向的结构的大小(以字节为单位);返回时,它将包含对等地址的实际大小。

如果提供的缓冲区太小,返回的地址会被截断;在这种情况下,< code>addrlen将返回一个大于提供给调用的值。

因此,总而言之,可能是第三个论点导致了你的EFAULT - 而不是第二个。这由您的桁架输出支持,该输出显示addrlen作为0x10传递到内核:这通常不是有效的内存地址。

 类似资料:
  • 问题内容: TextMate似乎使用了我假定的内置Python版本(sys.path不起作用)。您如何配置它以使用3.1?我已经安装了3.1软件包,并且可以将IDLE用于交互式会话,但是现在需要使用TextMate。 谢谢 问题答案: TextMate使用变量的值来查找Python解释器的路径。一个好的解决方案是利用TextMate的能力来定义变量(例如基于每个项目): 打开一个新的或现有的Tex

  • 本文向大家介绍Python使用ctypes调用C/C++的方法,包括了Python使用ctypes调用C/C++的方法的使用技巧和注意事项,需要的朋友参考一下 python使用ctypes调用C/C++ 1. ctpes介绍 ctypes is a foreign function library for Python. It provides C compatible data types, a

  • 一方面,我有一个文本加密/解密与Perl的 另一方面,我有Python的PyCrypto,我需要它来解码来自Perl的数据,但也发送Perl密码可以在给定加密的情况下读取的文本。 我拥有来自Perl程序的密钥,并对Perl发送到Python系统的\u hex:ed密码短语进行加密。 但是Python似乎绝对希望有IV来完成它的工作 然而,documnetation似乎表明IV已经存在 “盐”——将

  • 问题内容: 我是Python的新手,并且开始自学使用PyQT4.7和Python 2.6进行GUI编程(希望如此) 我刚刚从PyQT网站下载了整个PyQT / QT4软件包(包括QTDesigner),但是看起来QTDesigner看起来像个新手,因为每个小部件都看起来很棒(因为您可以看到所有属性/属性/默认设置等)编辑属性很棒,但是PyQT似乎没有设置QTDesigner与PyQT和PyQTs

  • 问题内容: 我在SO上发现了其他几个有关JavaMail API和通过SMTP服务器发送邮件的问题,但是没有一个使用TLS安全性进行讨论。我正在尝试使用JavaMail通过我的工作SMTP邮件服务器向我发送状态更新,但是它需要TLS,而且我在网上找不到任何有关如何使用JavaMail访问需要TLS加密的SMTP服务器的示例。有人能帮忙吗? 问题答案: 实际上,我们的产品中确实有一些通知代码,如果有

  • 我已经阅读了一些关于SaaS/PaaS/IaaS的信息,我在想: 如果我提供了一个SaaS应用程序,我的客户能否使用PaaS开发和部署他自己的应用程序,PaaS将使用一些API与我的SaaS应用程序交互?还是我对云服务的理解有误?