使用ctypes和python并调用libc accept时的EFAULT
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用ctypes和python并调用libc accept时的EFAULT相关的知识,希望对你有一定的参考价值。
创建套接字时,普通的python套接字模块不支持除AF_INET之外的协议:
从python socket module.c:
- a中仅支持AF_INET,AF_INET6和AF_UNIX地址系列 虽然支持AF_PACKET,AF_NETLINK和AF_TIPC,但便携式更少 在Linux下。
所以我已经开始使用ctypes手动调用正常的BSD套接字库的套接字,绑定,监听和接受来自libc的调用。我可以创建套接字,将套接字绑定到一个地址,并将套接字置于监听模式,这需要转换对我所做的结构继承的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(错误号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。为什么我在这种情况下看到了EFAULT?如何使用ctypes分配python数据结构以允许内核将数据移动到用户空间?
我看到一个明显的问题。我已成功使用ctypes
但不能声称自己是专家,因此可能还有其他一些问题。
我认为你必须在某个地方为libc.accept
定义参数原型,但这不在你发布的源代码中,所以我认为它是正确的。假设原型与libc绑定一致:accept's
第三个参数(addrlen
)是指向socklen_t
的指针,但你只是传递一个长度(不是指向长度的指针)。
通常的方法是你创建一个socklen_t
变量并用你的addr
缓冲区的大小填充它,然后accept
(当它完成时)将对等体的地址复制到你的addr
缓冲区,截断它是否太大,但更新通过addrlen
与实际大小。来自(linux版本)accept(2)
:
addrlen
参数是一个value-result参数:调用者必须初始化它以包含addr
指向的结构的大小(以字节为单位);返回时它将包含对等地址的实际大小。如果提供的缓冲区太小,则截断返回的地址;在这种情况下,
addrlen
将返回一个大于提供给调用的值。
所以,总而言之,它可能是导致你的EFAULT
的第三个论点 - 而不是第二个。这是由你的truss
输出支持的,它显示addrlen
作为0x10
传递给内核:这通常不是有效的内存地址。
以上是关于使用ctypes和python并调用libc accept时的EFAULT的主要内容,如果未能解决你的问题,请参考以下文章